Recalling information from dictionaries within dictionaries - python

So say I have a number of dictionaries within a dictionary
d = {'a': {'name': bob, 'class': 2a}, 'b': {'name': mike, 'class': 2b}, 'c': {'name': ben, 'class': 2b}}
How would I go about identifying items within each of these internal dictionaries. Say I wanted to identify the keys of the internal dictionaries that were in 'class' '2b'. How would I code this so that it gave me the keys 'b' and 'c'???
Thanks in advance.

You need to loop over the keys of your dictionary and check each sub-dict.
[k for k in d if d[k]['class'] == '2b']
Out[16]: ['c', 'b']
optionally,
[k for k,v in d.items() if v['class'] == '2b']
Out[17]: ['c', 'b']

Related

Dictionary Comprehension in Python for key:[1,2,3] [duplicate]

This question already has answers here:
is it possible to reverse a dictionary in python using dictionary comprehension
(5 answers)
Closed 2 years ago.
While I've been improving my Python skills I have one question.
My code is below:
# def invertDictionary(dict):
# new_dict = {}
# for key, value in dict.items():
# if value in new_dict:
# new_dict[value].append(key)
# else:
# new_dict[value]=[key]
# return new_dict
def invertDictionary(dict):
new_dict = {value:([key] if value else [key]) for key, value in dict.items()}
return new_dict;
invertDictionary({'a':3, 'b':3, 'c':3})
I am trying to get output like {3:['a','b','c']}. I have achieved that using a normal for-loop; I just want to know how to get these results using a Dictionary Comprehension. I tried but in append it's getting an error. Please let me know how to achieve this.
Thanks in Advance!
You missed that you also need a list comprehension to build the list.
Iterate over the values in the dict, and build the needed list of keys for each one.
Note that this is a quadratic process, whereas the canonical (and more readable) for loop is linear.
d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
inv_dict = {v: [key for key, val in d.items() if val == v]
for v in set(d.values())}
result:
{0: ['g'],
3: ['a', 'b', 'c'],
4: ['e', 'f']
}
Will this do?
while your original version with a regular for loop is the best solution for this, here is a variation on #Prune answer that doesn't goes over the dict multiple times
>>> import itertools
>>> d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
>>> {group_key:[k for k,_ in dict_items]
for group_key,dict_items in itertools.groupby(
sorted(d.items(),key=lambda x:x[-1]),
key=lambda x:x[-1]
)
}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
first we sorted the items of the dict by value with a key function to sorted using a lambda function to extract the value part of the item tuple, then we use the groupby to group those with the same value together with the same key function and finally with a list comprehension extract just the key
--
as noted by Kelly, we can use the get method from the dict to get the value to make it shorter and use the fact that iteration over a dict give you its keys
>>> {k: list(g) for k, g in itertools.groupby(sorted(d, key=d.get), d.get)}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
You could use a defalutdict and the append method.
from collections import defaultdict
dict1 = {'a': 3, 'b': 3, 'c': 3}
dict2 = defaultdict(list)
{dict2[v].append(k) for k, v in dict1.items()}
dict2
>>> defaultdict(list, {3: ['a', 'b', 'c']})

Find top counted element in a dictionary of a dictionary

I have a dictionary of dictionary myDict:
myDict = { 'cow': {'A':2, 'B':5, 'C':3},
'cat': {'A':7, 'B':1, 'C':6},
'dog': {'A':1, 'B':4, 'C':3},
'bird': {'A':5, 'B':7, 'C':9}
}
I want to find the top count element for each animal in this case, i.e. the output should be:
myNewTable = {'cow':'B', 'cat':'A', 'dog':'B', 'bird':'C'}
I tried to achieve this using the following code:
myNewTable = max(x.items(), key=operator.itemgetter(1))[0] for x in myDict
but got the following error:
File "<ipython-input-11-3bcb909a6476>", line 28
myNewTable = max(x.items(), key=operator.itemgetter(1))[0] for x in myDict
^
SyntaxError: invalid syntax
What did I do wrong here ? And how could I fix this?
Well, your syntax is wrong, but you have the right idea. A nice and succinct solution using max and dict.get can be built on by iterating over myDict:
>>> {k : max(v, key=v.get) for k, v in myDict.items()}
{'bird': 'C', 'cat': 'A', 'cow': 'B', 'dog': 'B'}
You are using comprehension syntax but haven't wrapped it in a specific type (e.g. list => [], set => {}, dict => {:}). So fixing your code it would look like:
In []:
[max(myDict[x].items(), key=operator.itemgetter(1))[0] for x in myDict]
Out[]:
['B', 'A', 'B', 'C']
But you wanted it as a dict, so perhaps you meant:
In []:
{x: max(myDict[x].items(), key=operator.itemgetter(1))[0] for x in myDict}
Out[]:
{'bird': 'C', 'cat': 'A', 'cow': 'B', 'dog': 'B'}
But can be specified more succinctly (as per #coldspeed's answer):
{x: max(myDict[x], key=myDict[x].get) for x in myDict}
Another alternative using collections.Counter with its .most_common(...) method:
>>> from collections import Counter
>>> {k: Counter(v).most_common(1)[0][0] for k, v in myDict.items()}
{'cat': 'A', 'bird': 'C', 'cow': 'B', 'dog': 'B'}
This will be useful in general if you want to select more than one highest count elements from the nested dict. For example, below is the sample to select list of two most common keys in dict:
>>> {k: [x[0] for x in Counter(v).most_common(2)] for k, v in myDict.items()}
{'dog': ['B', 'C'], 'bird': ['C', 'B'], 'cat': ['A', 'C'], 'cow': ['B', 'C']}
From the Counter.most_common([n]) document:
Return a list of the n most common elements and their counts from the most common to the least. If n is omitted or None, most_common() returns all elements in the counter. Elements with equal counts are ordered arbitrarily:

Merge dictionaries with old keys when old value and new key is same

I want to merge two dictionaries like this:
old={'a':'1a','b':'1b','c':'1c'}
new={'1a':'c','1b':'d','1c':'e'}
I want output like this:
new_dict={'a':'c','b':'d','c':'e'}
Note: The length of both dictionaries is different.
How to do it in python?
With a dict-comprehension:
old = {'a': '1a','b': '1b','c': '1c'}
new = {'1a': 'c','1b': 'd','1c': 'e'}
res = {k: new[v] for k, v in old.items()} # if all values in `old` exist in `new` as keys.
res = {k: new.get(v, None) for k, v in old.items()} # if you cannot guarantee the above.
print(res) # {'b': 'd', 'a': 'c', 'c': 'e'}
*Note that the None parameter of the .get() method is the default one and as such, it can be omitted. I will leave it there though to remind you that you can specify anything you want depending on the specifics of your problem (e.g., '' (blank string) might be better in your case)
You can get the new dictionary using a dictionary comprehension where you get the values from the new dictionary based on the keys in the old dictionary. Be sure to use get which returns None by default if a value from the old dictionary is not present as a key in the new dictionary.
old = {'a': '1a', 'b': '1b' ,'c': '1c'}
new = {'1a': 'c', '1b': 'd', '1c': 'e'}
new_dict = {k: new.get(old[k]) for k in old}
>>> new_dict
{'a': 'c', 'b': 'd', 'c': 'e'}
You could use a dictionary comprehension that interprets the value of the first dictionary as the key of the second dictionary:
>>> {item: new[value] for item, value in old.items() if value in new}
{'a': 'c', 'b': 'd', 'c': 'e'}
In case you can garantuee that all values of old are in new you could omit the if value in new part.

list comprehension using dictionary entries

trying to figure out how I might be able to use list comprehension for the following:
I have a dictionary:
dict = {}
dict ['one'] = {"tag":"A"}
dict ['two'] = {"tag":"B"}
dict ['three'] = {"tag":"C"}
and I would like to create a list (let's call it "list") which is populated by each of the "tag" values of each key, i.e.
['A', 'B', 'C']
is there an efficient way to do this using list comprehension? i was thinking something like:
list = [x for x in dict[x]["tag"]]
but obviously this doesn't quite work. any help appreciated!
This is an extra step but gets the desired output and avoids using reserved words:
d = {}
d['one'] = {"tag":"A"}
d['two'] = {"tag":"B"}
d['three'] = {"tag":"C"}
new_list = []
for k in ('one', 'two', 'three'):
new_list += [x for x in d[k]["tag"]]
print(new_list)
Try this:
d = {'one': {'tag': 'A'},
'two': {'tag': 'B'},
'three': {'tag': 'C'}}
tag_values = [d[i][j] for i in d for j in d[i]]
>>> print tag_values
['C', 'B', 'A']
You can sort the list afterwards if it matters.
If you have other key/value pairs in the inner dicts, apart from 'tag', you may want to specify the 'tag' keys, like this:
tag_value = [d[i]['tag'] for i in d if 'tag' in d[i]]
for the same result. If 'tag' is definitely always there, remove the if 'tag' in d[i] part.
As a side note, never a good idea to call a list 'list', since it's a reserved word in Python.
You can try this:
[i['tag'] for i in dict.values()]
I would do something like this:
untransformed = {
'one': {'tag': 'A'},
'two': {'tag': 'B'},
'three': {'tag': 'C'},
'four': 'bad'
}
transformed = [value.get('tag') for key,value in untransformed.items() if isinstance(value, dict) and 'tag' in value]
It also sounds like you're trying to get some info out of JSON you might want to look into a tool like https://stedolan.github.io/jq/manual/

How to replace keys (key labels) in a dictionary from a list of tokens

I have a dictionary
dict = {'a': 'cat', 'b':'dog'}
and I want to replace the keys in the dict
with new keys (or key labels) from a list ['c', 'd'] so that I get (the same)
dict = {'c': 'cat', 'd':'dog'}. How can I do this?
You can define the relation between the old keys and their replacements, in another dictionary, like this. Here, mapping is the dictionary which maps the old keys with the new keys.
d, mapping = {'a': 'cat', 'b':'dog'}, {"a":"c", "b":"d"}
print {mapping[k]:v for k, v in d.items()}
Output
{'c': 'cat', 'd': 'dog'}
As already has been pointed out, a dictionary is not ordered. So if you want to replace your keys with values from a list (which is ordered), you will need to specify how the keys of your dict are ordered. Something along these lines:
def replaceKeys (d, newKeys, sort):
return {newKeys[idx]: v for idx, (_, v)
in enumerate(sorted(d.items(), key = lambda kv: sort(kv[0])))}
d = {'cat': 'gato', 'dog': 'chucho', 'mule': 'mula'}
d2 = replaceKeys(d, ['a', 'b', 'c'], lambda oldKey: oldKey) #sort alphabetically
print(d2)
d2 = replaceKeys(d, ['a', 'b', 'c'], lambda oldKey: -len(oldKey)) #sort by length ascending
print(d2)
d2 = replaceKeys(d, ['a', 'b', 'c'], lambda oldKey: oldKey[2]) #sort by third letter
print(d2)

Categories