Reputation: 301
I have multiple dictionaries which contain data depending of their business value, e.g.:
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
...
I need to check whether a variable x
is contained in any of these dictionaries, and to identify in which of these dictionaries it is contained. The number of such dictionaries can be huge, so checking them manually is not very effective. Is there something more pythonic than
if x in companies:
pass # do something
elif x in names:
pass # do something
...
Upvotes: 5
Views: 2317
Reputation: 26315
An easy way would be to put the dictionaries in a list, iterate each dictionary, and check if x
exists in each dictionary:
from json import dumps
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
lst = [companies, names]
x = 'google'
for dic in lst:
if x in dic:
print('%s exists in dict %s' %(key, dumps(dic)))
# google exists in dict {"google": "value_1", "facebook": "value_2"}
But this is slow because you need to iterate every dictionary in the list for a lookup. This will be O(D)
for each lookup, where D
is the number of dictionaries in the list.
A faster way would be to use a defaultdict(list)
to collect the dictionaries for each key, then subsequent look ups are O(1)
. However building this dictionary will be a O(D * K)
operation(D
= number of dictionaries, K
= number of keys per dictionary), because we need to iterate every dict and its keys. If your doing a lot of look ups then this conversion will be worthwhile in the long run.
from collections import defaultdict
from json import dumps
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
lst = [companies, names]
x = 'google'
all_dicts = defaultdict(list)
for dic in lst:
for key in dic:
all_dicts[key].append(dic)
print("%s exists in these dictionaries : %s" % (x, dumps(all_dicts[x])))
# google exists in these dictionaries : [{"google": "value_1", "facebook": "value_2"}]
Upvotes: 2
Reputation: 193
You could make a list with those dictionaries :
dictionaries = [companies, names]
for dictionary in dictionaries:
if keyword in dictionary:
Upvotes: 3
Reputation: 2260
Instead of looping over all the dictionaries every time for every x
you have, you could build a dictionary of all the keys, with the names of the dictionaries that have that key as value.
In this way you will loop once over all the dictionaries to build your 'look up table' and then every access to an 'x' won't need any looping anymore.
For example:
my_dicts = {'companies': {'google': 'value_1', 'facebook': 'value_2', 'alex': 'yo'},
'names': {'alex': 'value_3', 'john': 'value_4'}}
# build the lookup dict
lookup = {}
for dk, dv in my_dicts.items():
for k in dv.keys():
dl = lookup.get(k, [])
lookup[k] = dl + [dk]
Now you can directly access the dictionaries that have your x
key:
x = 'alex'
dict_names = lookup[x]
for dn in dict_names:
# do something on my_dict[dn]
print(dn)
companies names
Upvotes: 3
Reputation: 77107
Python dictionary keyview objects are actually set-like. You can make a set out of them easily:
>>> a = {'a':1, 'b':2}
>>> b = {'a':2, 'c':3}
>>> a.keys() | b.keys()
{'a', 'b', 'c'}
Now all you need to do is check membership in the set
>>> if x in that_set: ...
If you have a large number of dictionaries, you can look at this answer for how to make a union of many sets, but keep in mind that set.union(dict.keys())
is not legal...
>>> set.union(a.keys())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'union' for 'set' objects doesn't apply to a 'dict_keys' object
so you'd need to do something like
>>> all_keys = set.union(*(set(d) for d in all_dicts))
explicitly casting each dictionary to a set in the comprehension.
Of course, you could also merge all the dictionaries, to a similar effect:
>>> all_dicts = {**dict1, **dict2, **dict3}
>>> "key" in all_dicts
This is a still very efficient way to find at least one value in all the dictionaries for the given key, even though it still doesn't tell you which of the dictionaries the key was in. For that, I'm afraid you must iterate. azro's fine answer tells you how to do that.
Upvotes: 1
Reputation: 13106
I'd use a list
to hold all of the dictionaries, and then just filter out the ones that don't contain your key using a list comprehension:
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
x = 'john'
dicts = [companies, names]
contains_key = [d for d in dicts if x in d]
For a large number of dictionaries, say thousands, this doesn't scale as well as @Jean-François Fabre's answer, but it's a simple approach
Upvotes: 3
Reputation: 54148
The way to:
filter
to find the dicts where the search_key is innext()
to iterate once to get the first one (to get any in fact)default
param to avoid the StopIteration
(you can return dict also next(..., {})
def find_dict(x, *dicts):
return next(filter(lambda d: x in d, dicts), None)
Use :
if __name__ == '__main__':
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
x = 'alex'
print(find_dict(x, companies, names)) # {'alex': 'value_3', 'john': 'value_4'}
print(find_dict('foo', companies, names)) # None
Upvotes: 2
Reputation: 140168
Simple/quick to code: loop in the list of dictionaries, stop when you find it.
But complexity isn't good if you perform several searches. Instead, create a dictionary of your dictionaries.
like this:
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
import collections
c = collections.defaultdict(list)
for d in [companies,names]:
for k,v in d.items():
c[k].append((v,d))
now:
print(c.get('google'))
prints:
[('value_1', {'google': 'value_1', 'facebook': 'value_2'})
Now if I add a common key in both dicts:
names = {'alex': 'value_3', 'john': 'value_4', 'facebook':'value_5'}
print(c.get('facebook'))
we get a list of all values and the origin dictionaries:
[('value_2', {'google': 'value_1', 'facebook': 'value_2'}),
('value_5', {'alex': 'value_3', 'john': 'value_4', 'facebook': 'value_5'})]
With that solution, even if you have a lot of dictionaries, the lookup is always O(1)
once the new big dictionary is built. The build is amortized after 2 or 3 lookups.
Above, we see that the origin dictionary has been retained. Now you can choose how you identify this dictionary. I chose to put the reference itself as I had no constraint.
Upvotes: 4