This is how I have been searching for objects in python. Is there any more efficient (faster, simpler) way of doing it?
Obs: A is a known object.
for i in Very_Long_List_Of_Names:
if A == My_Dictionary[i]:
print: "The object you are looking for is ", i
break
The one liner would be: (i for i in List_of_names if A == My_dictionary[i]).next().
This throws a KeyError if there is an item in List_of_names that is not a key in My_dictionary and a StopIteration if the item is not found, else returns the key where it finds A.
I assume you're looking for an object in the values of a Python dictionary.
If you simply want to check for its existence (as in, you don't really care to know which key maps to that value), you can do:
if A in My_Dictionary.values():
print "The object is in the dictionary"
Otherwise, if you do want to get the key associated with that value:
for k, v in My_Dictionary.iteritems():
if v == A:
print "The object you are looking for is ", k
break
EDIT: Note that you can have multiple keys with the same value in the same dictionary. The above code will only find the first occurence. Still, it sure beats having a huge list of names. :-)
Seems to me like you have you're using the dictionary incorrectly if you're searching through all the keys looking for a specific value.
If A is hashable, then store A in a dictionary with its values as i.
d = {A: 'a_name'}
If My_Dictionary is not huge and can trivially fit in memory, and, A is hashable, then, create a duplicate dictionary from it:
d = dict((value, key) for key, value in My_Dictionary.iteritems())
if A in d:
print "word you're looking for is: ", d[A]
Otherwise, you'll have to to iterate over every key:
for word, object_ in My_Dictionary.iteritems():
if object_ == A:
print "word you're looking for is: ", word
Related
How do I print the number of items with 'for loops' in a list and dictionary?
Here's my code:
for key, val in i.items():
print(key, val)
q = ["Quests: ", "Look at inventory, ", "Press 'r' or 'l'."]
for x in q:
print(x)
Printing the number of items in the dictionary:
print(len(i.keys()))
Printing the number of items in the list:
print(len(q))
Not sure why you'd need a for loop though.
Not sure I understand but try that:
len(i)
This equals the length of dictionary 'i'.
AKA number of items in it.
I assume you are new to Python, since most tutorials on Python cover this basic concept pretty quickly.
If I understand your question correctly, you are trying something like:
for i in range(len(a_list)):
print(i)
You could then also access each item of a list with: a_list[i]
Note that this will not work the same way with a dictionary. a_dictionary[i] would not get the ith element. It would instead look for a key with the value i.
I'd suggest you follow one of the many helpful tutorials online.
There's two ways. The simplest is to use the length function len(). len(yourList) and len(yourDictionary) will give their sizes, aka the number of items in them.
However to do this manually, in case you iterate only part of a list you just create a counter variable.
so
counter = 0
for key, value in i.items():
print(key, value)
counter += 1
print(counter)
I tried to parse json and use for loop in Python.
obj is json and as you know it is like dictionary in list in dictionary in dictionary...and so on.
So I parse json and make it as a for loop like this:
all = obj['products']
for a in obj:
recommendSellerScore.append(a['recommendSellerScore'])
However, the problem is 'recommendSellerScore' which is key does not exist in some lists.
What I want as a result is to print 'None' where recommendSellerScore does not exist, and print values where recommendSellerScore does exist.
for a in all:
if a['recommendSellerScore'] in all:
recommendSellerScore.append(a['recommendSellerScore'])
else:
continue
print('None')
I ran this code above, but got an Error because 'recommendSellerScore' does not exist.
for a in all:
if ['recommendSellerScore'] in all:
recommendSellerScore.append(a['recommendSellerScore'])
else:
continue
print('None')
This one worked, however, since 'recommendSellerScore' exists in list in dictionary, it was not iterable. (I guess)
Please fix my code, and any comments or advice will be appreciated!
Here is fixed version of your code (I took out the continue statement and the [] around the string):
for a in all:
if "recommendSellerScore" in a:
recommendSellerScore.append(a["recommendSellerScore"])
else:
print("None")
Maybe something like the code below works for you?
for a in all:
if a.get(['recommendSellerScore']) is not None:
recommendSellerScore.append(a['recommendSellerScore'])
else:
print("None")
# No need for continue here.
You can use get method of dictionaries to try to access the dictionary value, if the key is not present you can provide a default value, if you don't specify one, it will output None, for example:
key = 'recommendSellerScore'
a = [{key: 1}, {}]
recommendSellerScore = []
for d in a:
score = d.get(key)
if score is not None:
print(score)
recommendSellerScore.append(score)
else:
print('None')
Edit: as pointed by #kederrac if your data can have {key: None} values and you are interested in keeping those None values then it's best to ask if the key is truly present in the dictionary, for example:
key = 'recommendSellerScore'
a = [{key: 1}, {key: None}]
recommendSellerScore = []
for d in a:
if key in d.keys():
print(d[key])
recommendSellerScore.append(d[key])
else:
print('None')
It will print:
>>> 1
>>> None
I want to check if the 'value' exists in python dictionary and if matches print the 'key'. The problem is, values are in the list.
This script will give the server name based on the provided domain name. It will query the predefined nameserver and gives output accordingly.
I have tried following but it keeps giving me the same output.
if [k for k, v in servers.iteritems() if answer in v]:
print "\nThe domain is in " + v + ".\n"
The script is as follows. Any suggestions other than the original one is welcome.
#!/usr/bin/python
import dns.resolver
import sys
servers = {
'UK':['127.0.0.1'],
'USA':['127.0.0.2','127.0.0.3','127.0.0.4'],
'AUS':['127.0.1.1','127.0.1.2']
}
website = sys.argv[1]
try:
nameserver = dns.resolver.Resolver(configure=False)
nameserver.nameservers = ['198.40.3.6','198.40.3.7']
answer = nameserver.query(website)[0]
answer = str(answer)
if [k for k, v in servers.iteritems() if answer in v]:
print "\nThe domain is in " + v + ".\n"
except Exception as e:
print str(e)
It should give the correct 'key' but it is not. It is giving the same output.
The logic of your if check and the print statement following it are faulty. There's nothing specifically incorrect about how you're finding keys (though you could do it more efficiently), but you're not using that result at all in the rest of your code, so it doesn't really matter.
Try changing your code to this:
matched_keys = [k for k, v in servers.iteritems() if answer in v] # same list comp as before
if matched_keys:
print print "\nThe domain is in " + str(matched_keys) + ".\n" # or maybe use matched_keys[0]?
The way I coded it above will print out the list of all keys that have the answer in them, if there are any. If you're sure there can only be one result, you can use matched_keys[0].
Note that if you expect to be doing this sort of check a lot, with the same set of servers, you should probably change your data structure so that you can do a more efficient check. The current one is O(M*N) where M is the number of checks you need to do and M is the number of values in the dictionary. You could turn that into O(M) by constructing a reversed dictionary:
reversed_servers = {}
for k, v in servers.iteritems():
for address in v:
reversed_servers.setdefault(address, []).append(k) # or reversed_servers[address] = k
You only need to do this setup once. Later you can do any number of efficent lookups with just reversed_servers[answer], with no loop needed.
Note that the code above sets up a dictionary containing lists of all matching keys, if there can be only one for each address (because the values are unique), then you can use the alternative version in the comment, which will map from address to key directly (without a list).
Try this:
result = [k for k in servers.keys() if answer in servers[k]]
if result:
print "\nThe domain is in " + str(servers[result[0]]) + ".\n"
To print the corresponding key, you can use result[0].
I am parsing unknown nested json object, I do not know the structure nor depth ahead of time. I am trying to search through it to find a value. This is what I came up with, but I find it fugly. Could anybody let me know how to make this look more pythonic and cleaner?
def find(d, key):
if isinstance(d, dict):
for k, v in d.iteritems():
try:
if key in str(v):
return 'found'
except:
continue
if isinstance(v, dict):
for key,value in v.iteritems():
try:
if key in str(value):
return "found"
except:
continue
if isinstance(v, dict):
find(v)
elif isinstance(v, list):
for x in v:
find(x)
if isinstance(d, list):
for x in d:
try:
if key in x:
return "found"
except:
continue
if isinstance(v, dict):
find(v)
elif isinstance(v, list):
for x in v:
find(x)
else:
if key in str(d):
return "found"
else:
return "Not Found"
It is generally more "Pythonic" to use duck typing; i.e., just try to search for your target rather than using isinstance. See What are the differences between type() and isinstance()?
However, your need for recursion makes it necessary to recurse the values of the dictionaries and the elements of the list. (Do you also want to search the keys of the dictionaries?)
The in operator can be used for both strings, lists, and dictionaries, so no need to separate the dictionaries from the lists when testing for membership. Assuming you don't want to test for the target as a substring, do use isinstance(basestring) per the previous link. To test whether your target is among the values of a dictionary, test for membership in your_dictionary.values(). See Get key by value in dictionary
Because the dictionary values might be lists or dictionaries, I still might test for dictionary and list types the way you did, but I mention that you can cover both list elements and dictionary keys with a single statement because you ask about being Pythonic, and using an overloaded oeprator like in across two types is typical of Python.
Your idea to use recursion is necessary, but I wouldn't define the function with the name find because that is a Python built-in which you will (sort of) shadow and make the recursive call less readable because another programmer might mistakenly think you're calling the built-in (and as good practice, you might want to leave the usual access to the built in in case you want to call it.)
To test for numeric types, use `numbers.Number' as described at How can I check if my python object is a number?
Also, there is a solution to a variation of your problem at https://gist.github.com/douglasmiranda/5127251 . I found that before posting because ColdSpeed's regex suggestion in the comment made me wonder if I were leading you down the wrong path.
So something like
import numbers
def recursively_search(object_from_json, target):
if isinstance(object_from_json, (basestring, numbers.Number)):
return object_from_json==target # the recursion base cases
elif isinstance(object_from_json, list):
for element in list:
if recursively_search(element, target):
return True # quit at first match
elif isinstance(object_from_json, dict):
if target in object_from_json:
return True # among the keys
else:
for value in object_from_json.values():
if recursively_search(value, target):
return True # quit upon finding first match
else:
print ("recursively_search() did not anticipate type ",type(object_from_json))
return False
return False # no match found among the list elements, dict keys, nor dict values
I have code that works but I'm wondering if there is a more pythonic way to do this. I have a dictionary and I want to see if:
a key exists
that value isn't None (NULL from SQL in this case)
that value isn't simply quote quote (blank?)
that value doesn't solely consist of spaces
So in my code the keys of "a", "b", and "c" would succeed, which is correct.
import re
mydict = {
"a":"alpha",
"b":0,
"c":False,
"d":None,
"e":"",
"g":" ",
}
#a,b,c should succeed
for k in mydict.keys():
if k in mydict and mydict[k] is not None and not re.search("^\s*$", str(mydict[k])):
print(k)
else:
print("I am incomplete and sad")
What I have above works, but that seems like an awfully long set of conditions. Maybe this simply is the right solution but I'm wondering if there is a more pythonic "exists and has stuff" or better way to do this?
UPDATE
Thank you all for wonderful answers and thoughtful comments. With some of the points and tips, I've updated the question a little bit as there some conditions I didn't have which should also succeed. I have also changed the example to a loop (just easier to test right?).
Try to fetch the value and store it in a variable, then use object "truthyness" to go further on with the value
v = mydict.get("a")
if v and v.strip():
if "a" is not in the dict, get returns None and fails the first condition
if "a" is in the dict but yields None or empty string, test fails, if "a" yields a blank string, strip() returns falsy string and it fails too.
let's test this:
for k in "abcde":
v = mydict.get(k)
if v and v.strip():
print(k,"I am here and have stuff")
else:
print(k,"I am incomplete and sad")
results:
a I am here and have stuff
b I am incomplete and sad # key isn't in dict
c I am incomplete and sad # c is None
d I am incomplete and sad # d is empty string
e I am incomplete and sad # e is only blanks
if your values can contain False, 0 or other "falsy" non-strings, you'll have to test for string, in that case replace:
if v and v.strip():
by
if v is not None and (not isinstance(v,str) or v.strip()):
so condition matches if not None and either not a string (everything matches) or if a string, the string isn't blank.
The get method for checking if a key exists is more efficient that iterating through the keys. It checks to see if the key exists without iteration using an O(1) complexity as apposed to O(n). My preferred method would look something like this:
if mydict.get("a") is not None and str(mydict.get("a")).replace(" ", "") != '':
# Do some work
You can use a list comprehension with str.strip to account for whitespace in strings.
Using if v is natural in Python to cover False-like objects, e.g. None, False, 0, etc. So note this only works if 0 is not an acceptable value.
res = [k for k, v in mydict.items() if (v.strip() if isinstance(v, str) else v)]
['a']
Here's a simple one-liner to check:
The key exists
The key is not None
The key is not ""
bool(myDict.get("some_key"))
As for checking if the value contains only spaces, you would need to be more careful as None doesn't have a strip() method.
Something like this as an example:
try:
exists = bool(myDict.get('some_key').strip())
except AttributeError:
exists = False
Well I have 2 suggestions to offer you, especially if your main issue is the length of the conditions.
The first one is for the check if the key is in the dict. You don't need to use "a" in mydict.keys() you can just use "a" in mydict.
The second suggestion to make the condition smaller is to break down into smaller conditions stored as booleans, and check these in your final condition:
import re
mydict = {
"a":"alpha",
"c":None,
"d":"",
"e":" ",
}
inKeys = True if "a" in mydict else False
isNotNone = True if mydict["a"] is not None else False
isValidKey = True if not re.search("^\s*$", mydict["a"]) else False
if inKeys and isNotNone and isValidKey:
print("I am here and have stuff")
else:
print("I am incomplete and sad")
it check exactly for NoneType not only None
from types import NoneType # dont forget to import this
mydict = {
"a":"alpha",
"b":0,
"c":False,
"d":None,
"e":"",
"g":" ",
}
#a,b,c should succeed
for k in mydict:
if type(mydict[k]) != NoneType:
if type(mydict[k]) != str or type(mydict[k]) == str and mydict[k].strip():
print(k)
else:
print("I am incomplete and sad")
else:
print("I am incomplete and sad")
cond is a generator function responsible for generating conditions to apply in a short-circuiting manner using the all function. Given d = cond(), next(d) will check if a exists in the dict, and so on until there is no condition to apply, in that case all(d) will evaluate to True.
mydict = {
"a":"alpha",
"c":None,
"d":"",
"e":" ",
}
def cond ():
yield 'a' in mydict
yield mydict ['a']
yield mydict ['a'].strip ()
if all (cond ()):
print("I am here and have stuff")
else:
print("I am incomplete and sad")