Let's say I have this dictionary:
>>> dic = {('a', 'l'):3, ('a', 'p'):2, ('b', 'l'):4, ('b', 'p'):1}
How can I edit it so I can have it like this:
>>> dic_new = {'a':{'l':3, 'p':2}, 'b':{'l':4, 'p':1}}
Whenever I change the keys I get an error. I am confused.
In each case, you want to set d2[k1][k2]=v whereever you have d1[k1,k2]=v. The simplest way to do this is to start with a defaultdict.
>>> from collections import defaultdict
>>> d1 = {('a', 'l'):3, ('a', 'p'):2, ('b', 'l'):4, ('b', 'p'):1}
>>> d2 = defaultdict(dict)
>>> for k1, k2 in d1:
... d2[k1][k2] = d[k1,k2]
...
>>> d2
defaultdict(<class 'dict'>, {'a': {'l': 3, 'p': 2}, 'b': {'l': 4, 'p': 1}})
>>> dict(d2)
{'a': {'l': 3, 'p': 2}, 'b': {'l': 4, 'p': 1}}
If you don't want to use a defaultdict, use the setdefault method.
d2 = {}
for k1, k2 in d1:
d2.setdefault(k1, {})[k2] = d1[k1,k2]
You can iterate through the original dictionary and create a new one as you find keys:
dic = {('a', 'l'):3, ('a', 'p'):2, ('b', 'l'):4, ('b', 'p'):1}
dic_new = {}
for (new_key, new_sub_key),value in dic.items():
if new_key not in dic_new:
dic_new[new_key] = {}
dic_new[new_key][new_sub_key] = value
print(dic_new)
Output
{'a': {'l': 3, 'p': 2}, 'b': {'l': 4, 'p': 1}}
You can use groupby + OrderedDict:
from itertools import groupby
from collections import OrderedDict
dic = {('a', 'l'):3, ('a', 'p'):2, ('b', 'l'):4, ('b', 'p'):1}
dic = OrderedDict(dic)
new_d = {}
for k, g in groupby(dic, lambda x: x[0]):
for x in g:
if k in new_d:
new_d[k].update({x[1]: dic[x]})
else:
new_d[k] = {x[1]: dic[x]}
print(new_d)
# {'a': {'l': 3, 'p': 2}, 'b': {'l': 4, 'p': 1}}
Or in case where you can guarantee dictionaries are ordered as per first value in tuple key, you can straightaway ignore OrderedDict.
Related
I have a loop:
all_rec = {}
for i in range(0, 2):
rec = buildings[best_buildings[i]]['recommendations']
The value of 'rec' after first iteration:
rec = {'a': {'b': 2, 'c': 1}, 'd': {'e': 5}}
The value of 'rec' after second iteration:
rec = {'d': {'e': 4}}
The data type of 'recommendations' is a dictionary. How can I add all the 'rec' dictionaries resulting from this loop into one dictionary 'all_rec'?
I want 'all_rec' to look like this:
all_rec = {'a': {'b': 2, 'c': 1}, 'd': {'e': 5}, 'd': {'e': 4}}
Keeping both 'd': {'e': 5} and 'd': {'e': 4} in the new dictionary. How can I do that in Python 2.7?
If you need to keep all such values, it suggests that the values in the lower dictionaries should be lists, at least for the summary list:
all_rec = {}
for i in range(0, 2):
rec = buildings[best_buildings[i]]['recommendations']
for dk, dc in rec.items():
if dk not in all_rec:
all_rec[dk] = {k:[v] for k,v in dc.items()}
else:
for k,v in dc.items():
if k in all_rec[dk]:
all_rec[dk][k].append(v)
else:
all_rec[dk][k] = [v]
print(all_rec)
{'a': {'b': [2], 'c': [1]}, 'd': {'e': [5,4]}}
This is Python 3.7; I don't know how you'd need to adjust to use 2.7 but I kept it as basic as possible.
I do not have your data but this is the rough idea:
If you want to sum the recommentations:
from collections import defaultdict
all_rec = defaultdict(lambda: defaultdict(int))
for i in range(0, 2):
rec[buildings[best_buildings[i]]] += buildings[best_buildings[i]]['recommendations']
If you want to append the recommendations:
from collections import defaultdict
all_rec = defaultdict(lambda: defaultdict(list))
for i in range(0, 2):
rec[buildings[best_buildings[i]]].append(buildings[best_buildings[i]]['recommendations'])
---
DEMO
>>> from collections import defaultdict
>>>
>>> demo = defaultdict(lambda: defaultdict(int))
>>> demo['a']['b'] += 1
>>> demo
defaultdict(<function <lambda> at 0x7f931a2d2700>, {'a': defaultdict(<class 'int'>, {'b': 1})})
>>> demo['a']['b'] += 1
>>> demo
defaultdict(<function <lambda> at 0x7f931a2d2700>, {'a': defaultdict(<class 'int'>, {'b': 2})})
>>>
>>> demo = defaultdict(lambda: defaultdict(list))
>>> demo['a']['b'].append(1)
>>> demo
defaultdict(<function <lambda> at 0x7f931a2d2b80>, {'a': defaultdict(<class 'list'>, {'b': [1]})})
>>> demo['a']['b'].append(1)
>>> demo
defaultdict(<function <lambda> at 0x7f931a2d2b80>, {'a': defaultdict(<class 'list'>, {'b': [1, 1]})})
>>>
The syntax of printing a normal dictionary is
{'a': 1, 'c': 3, 'b': 2}
Whereas
The syntax of printing a OrderedDict is
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
Is there any way where i can print/return the OrderedDict in the Normal Dictionary way??
Use a custom __str__ method in your own OrderedDict class ; in the custom method, you can build the string you want:
from collections import OrderedDict
class MyOrderedDict(OrderedDict):
def __str__(self):
return "{%s}" % ", ".join([repr(k)+": "+str(v) for k, v in self.iteritems()])
d = MyOrderedDict([('a', 1), ('b', 2), ('c', 3)])
The easy way:
from collections import OrderedDict
a = {'a': 1, 'c': 3, 'b': 2}
new_dict = dict(OrderedDict(a))
print(new_dict)
print(type(new_dict))
Output:
{'a': 1, 'c': 3, 'b': 2}
<type 'dict'>
The hard way:
You can also return the OrderedDict to a simple dict using groupby from itertools module like this way:
from collections import OrderedDict
from itertools import groupby
a = {'a': 1, 'c': 3, 'b': 2}
new_dict = {key:list(val)[0][1] for key, val in groupby(OrderedDict(a).items(), lambda x : x[0])}
print(new_dict)
print(type(new_dict))
Output:
{'c': 3, 'a': 1, 'b': 2`}
<type 'dict'>
Edit:
I see that there is some downvotes because they think that the output should be an ordered string. So, this is how do deal with it:
from collections import OrderedDict
a = {'a': 1, 'c': 3, 'b': 2}
new_dict = OrderedDict(a)
b = "{%s}" % ", ".join([str(key)+":"+str(val) for key, val in sorted(new_dict.iteritems())])
print(b)
print(type(b))
Output:
{'a':1, 'b':2, 'c':3}
<type 'str'>
To print OrderedDict in a dict-way you can act like this (of course, if the actual order of the items does not matter to print):
def some_function():
d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
od = OrderedDict(sorted(d.items(), key=lambda t: t[0]))
return od
my_ordered_dict_variable = some_function()
print('My Ordered Dicdict:', dict(my_ordered_dict_variable))
This code will print:
{'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
So I have this block of code
dictionary = {
'key1': {'a': 1, 'b': 2, 'c': 10},
'key2': {'d': 1, 'e': 1, 'c': 11},
'key3': {'d': 2, 'b': 1, 'g': 12}}
and
list1 = (a,b,c)
What I want to do is run a loop that finds the maximums of all the items in the list and returns the key. So for example, the maximum of 'c' would return 'key2', the maximum of 'b' would return 'key1', etc.
So far I have
for value in list1:
m = max(dictionary, key=lambda v: dictionary[v][value])
print(m + "\n")
But this only works if the same subkey exists in all keys in the dictionary. Any ideas on what to do?
Use float('-inf') when the key is missing:
m = max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf')))
Negative infinity is guaranteed to be smaller than any existing value in the dictionaries, ensuring that nested dictionaries with the specific key missing are ignored.
Demo:
>>> dictionary = {
... 'key1': {'a': 1, 'b': 2, 'c': 10},
... 'key2': {'d': 1, 'e': 1, 'c': 11},
... 'key3': {'d': 2, 'b': 1, 'g': 12}}
>>> list1 = ('a', 'b', 'c')
>>> for value in list1:
... print(value, max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf'))))
...
a key1
b key1
c key2
However, it'll be more efficient if you looped over all your dictionary values just once instead:
maximi = dict.fromkeys(list1, (None, float('-inf')))
for key, nested in dictionary.items():
for k in nested.keys() & maximi: # intersection of keys
if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
maximi[k] = (key, nested[k])
for value in list1:
print(value, maximi[value][0])
That's presuming you are using Python 3; in Python 2, replace .items() with .iteritems() and .keys() with .viewkeys().
Demo:
>>> maximi = dict.fromkeys(list1, (None, float('-inf')))
>>> for key, nested in dictionary.items():
... for k in nested.keys() & maximi: # intersection of keys
... if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
... maximi[k] = (key, nested[k])
...
>>> maximi
{'a': ('key1', 1), 'b': ('key1', 2), 'c': ('key2', 11)}
>>> for value in list1:
... print(value, maximi[value][0])
...
a key1
b key1
c key2
So I have this block of code
dictionary = {
'key1': {'a': 1, 'b': 2, 'c': 10},
'key2': {'d': 1, 'e': 1, 'c': 11},
'key3': {'d': 2, 'b': 1, 'g': 12}}
and
list1 = (a,b,c)
What I want to do is run a loop that finds the maximums of all the items in the list and returns the key. So for example, the maximum of 'c' would return 'key2', the maximum of 'b' would return 'key1', etc.
So far I have
for value in list1:
m = max(dictionary, key=lambda v: dictionary[v][value])
print(m + "\n")
But this only works if the same subkey exists in all keys in the dictionary. Any ideas on what to do?
Use float('-inf') when the key is missing:
m = max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf')))
Negative infinity is guaranteed to be smaller than any existing value in the dictionaries, ensuring that nested dictionaries with the specific key missing are ignored.
Demo:
>>> dictionary = {
... 'key1': {'a': 1, 'b': 2, 'c': 10},
... 'key2': {'d': 1, 'e': 1, 'c': 11},
... 'key3': {'d': 2, 'b': 1, 'g': 12}}
>>> list1 = ('a', 'b', 'c')
>>> for value in list1:
... print(value, max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf'))))
...
a key1
b key1
c key2
However, it'll be more efficient if you looped over all your dictionary values just once instead:
maximi = dict.fromkeys(list1, (None, float('-inf')))
for key, nested in dictionary.items():
for k in nested.keys() & maximi: # intersection of keys
if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
maximi[k] = (key, nested[k])
for value in list1:
print(value, maximi[value][0])
That's presuming you are using Python 3; in Python 2, replace .items() with .iteritems() and .keys() with .viewkeys().
Demo:
>>> maximi = dict.fromkeys(list1, (None, float('-inf')))
>>> for key, nested in dictionary.items():
... for k in nested.keys() & maximi: # intersection of keys
... if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
... maximi[k] = (key, nested[k])
...
>>> maximi
{'a': ('key1', 1), 'b': ('key1', 2), 'c': ('key2', 11)}
>>> for value in list1:
... print(value, maximi[value][0])
...
a key1
b key1
c key2
I used the sample from the documentation:
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
How can I make the result to be:
{ 'a': 5, 'r' :2 , 'b' :2}
supposing that we want to keep the Counter().most_common() code?
dict will do this easily:
>>> dict(Counter('abracadabra').most_common(3))
{'a': 5, 'r': 2, 'b': 2}
>>>
For further reference, here is part of what is returned by help(dict):
dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
The easiest way is to simply use dict()
dict(Counter('abracadabra').most_common(3))
Output:
{'a': 5, 'r': 2, 'b': 2}