Related
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.
I'm pulling data from the database and assuming i have something like this:
Product Name Quantity
a 3
a 5
b 2
c 7
I want to sum the Quantity based on Product name, so this is what i want:
product = {'a':8, 'b':2, 'c':7 }
Here's what I'm trying to do after fetching the data from the database:
for row in result:
product[row['product_name']] += row['quantity']
but this will give me: 'a'=5 only, not 8.
Option 1: pandas
This is one way, assuming you begin with a pandas dataframe df. This solution has O(n log n) complexity.
product = df.groupby('Product Name')['Quantity'].sum().to_dict()
# {'a': 8, 'b': 2, 'c': 7}
The idea is you can perform a groupby operation, which produces a series indexed by "Product Name". Then use the to_dict() method to convert to a dictionary.
Option 2: collections.Counter
If you begin with a list or iterator of results, and wish to use a for loop, you can use collections.Counter for O(n) complexity.
from collections import Counter
result = [['a', 3],
['a', 5],
['b', 2],
['c', 7]]
product = Counter()
for row in result:
product[row[0]] += row[1]
print(product)
# Counter({'a': 8, 'c': 7, 'b': 2})
Option 3: itertools.groupby
You can also use a dictionary comprehension with itertools.groupby. This requires sorting beforehand.
from itertools import groupby
res = {i: sum(list(zip(*j))[1]) for i, j in groupby(sorted(result), key=lambda x: x[0])}
# {'a': 8, 'b': 2, 'c': 7}
If you insist on using loops, you can do this:
# fake data to make the script runnable
result = [
{'product_name': 'a', 'quantity': 3},
{'product_name': 'a', 'quantity': 5},
{'product_name': 'b', 'quantity': 2},
{'product_name': 'c', 'quantity': 7}
]
# solution with defaultdict and loops
from collections import defaultdict
d = defaultdict(int)
for row in result:
d[row['product_name']] += row['quantity']
print(dict(d))
The output:
{'a': 8, 'b': 2, 'c': 7}
Since you mention pandas
df.set_index('ProductName').Quantity.sum(level=0).to_dict()
Out[20]: {'a': 8, 'b': 2, 'c': 7}
Use tuple to store the result.
Edit:
Not clear if the data mentioned is really a dataframe.
If yes then li = [tuple(x) for x in df.to_records(index=False)]
li = [('a', 3), ('a', 5), ('b', 2), ('c', 7)]
d = dict()
for key, val in li:
val_old = 0
if key in d:
val_old = d[key]
d[key] = val + val_old
print(d)
Output
{'a': 8, 'b': 2, 'c': 7}
If I have a dictionary like:
{'a': 1, 'b': 2, 'c': 3}
How can I convert it to this?
[('a', 1), ('b', 2), ('c', 3)]
And how can I convert it to this?
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> list(d.items())
[('a', 1), ('c', 3), ('b', 2)]
For Python 3.6 and later, the order of the list is what you would expect.
In Python 2, you don't need list.
since no one else did, I'll add py3k versions:
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> list(d.items())
[('a', 1), ('c', 3), ('b', 2)]
>>> [(v, k) for k, v in d.items()]
[(1, 'a'), (3, 'c'), (2, 'b')]
You can use list comprehensions.
[(k,v) for k,v in a.iteritems()]
will get you [ ('a', 1), ('b', 2), ('c', 3) ] and
[(v,k) for k,v in a.iteritems()]
the other example.
Read more about list comprehensions if you like, it's very interesting what you can do with them.
Create a list of namedtuples
It can often be very handy to use namedtuple. For example, you have a dictionary of 'name' as keys and 'score' as values like:
d = {'John':5, 'Alex':10, 'Richard': 7}
You can list the items as tuples, sorted if you like, and get the name and score of, let's say the player with the highest score (index=0) very Pythonically like this:
>>> player = best[0]
>>> player.name
'Alex'
>>> player.score
10
How to do this:
list in random order or keeping order of collections.OrderedDict:
import collections
Player = collections.namedtuple('Player', 'name score')
players = list(Player(*item) for item in d.items())
in order, sorted by value ('score'):
import collections
Player = collections.namedtuple('Player', 'score name')
sorted with lowest score first:
worst = sorted(Player(v,k) for (k,v) in d.items())
sorted with highest score first:
best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)
[(k,v) for (k,v) in d.iteritems()]
and
[(v,k) for (k,v) in d.iteritems()]
What you want is dict's items() and iteritems() methods. items returns a list of (key,value) tuples. Since tuples are immutable, they can't be reversed. Thus, you have to iterate the items and create new tuples to get the reversed (value,key) tuples. For iteration, iteritems is preferable since it uses a generator to produce the (key,value) tuples rather than having to keep the entire list in memory.
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = { 'a': 1, 'b': 2, 'c': 3 }
>>> a.items()
[('a', 1), ('c', 3), ('b', 2)]
>>> [(v,k) for (k,v) in a.iteritems()]
[(1, 'a'), (3, 'c'), (2, 'b')]
>>>
These are the breaking changes from Python 3.x and Python 2.x
For Python3.x use
dictlist = []
for key, value in dict.items():
temp = [key,value]
dictlist.append(temp)
For Python 2.7 use
dictlist = []
for key, value in dict.iteritems():
temp = [key,value]
dictlist.append(temp)
>>> a={ 'a': 1, 'b': 2, 'c': 3 }
>>> [(x,a[x]) for x in a.keys() ]
[('a', 1), ('c', 3), ('b', 2)]
>>> [(a[x],x) for x in a.keys() ]
[(1, 'a'), (3, 'c'), (2, 'b')]
By keys() and values() methods of dictionary and zip.
zip will return a list of tuples which acts like an ordered dictionary.
Demo:
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> zip(d.keys(), d.values())
[('a', 1), ('c', 3), ('b', 2)]
>>> zip(d.values(), d.keys())
[(1, 'a'), (3, 'c'), (2, 'b')]
A alternative one would be
list(dictionary.items()) # list of (key, value) tuples
list(zip(dictionary.values(), dictionary.keys())) # list of (value, key) tuples
d = {'John':5, 'Alex':10, 'Richard': 7}
list = []
for i in d:
k = (i,d[i])
list.append(k)
print list
Python3 dict.values() not return a list. This is the example
mydict = {
"a": {"a1": 1, "a2": 2},
"b": {"b1": 11, "b2": 22}
}
print(mydict.values())
> output: dict_values([{'a1': 1, 'a2': 2}, {'b1': 11, 'b2': 22}])
print(type(mydict.values()))
> output: <class 'dict_values'>
print(list(mydict.values()))
> output: [{'a1': 1, 'a2': 2}, {'b1': 11, 'b2': 22}]
print(type(list(mydict.values())))
> output: <class 'list'>
x = {'a': 1, 'b': 2, 'c': 4, 'd':3}
sorted(map(lambda x : (x[1],x[0]),x.items()),key=lambda x : x[0])
Lets break the above code into steps
step1 = map(lambda x : (x[1],x[0]),x.items())
x[1] : Value
x[0] : Key
Step1 will create a list of tuples containing pairs in the form of (value,key) e.g. (4,'c')
step2 = sorted(step1,key=lambda x : x[0])
Step2 take the input of from Step 1 and sort using the 1st value of the tuple
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}
If I have a dictionary like:
{'a': 1, 'b': 2, 'c': 3}
How can I convert it to this?
[('a', 1), ('b', 2), ('c', 3)]
And how can I convert it to this?
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> list(d.items())
[('a', 1), ('c', 3), ('b', 2)]
For Python 3.6 and later, the order of the list is what you would expect.
In Python 2, you don't need list.
since no one else did, I'll add py3k versions:
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> list(d.items())
[('a', 1), ('c', 3), ('b', 2)]
>>> [(v, k) for k, v in d.items()]
[(1, 'a'), (3, 'c'), (2, 'b')]
You can use list comprehensions.
[(k,v) for k,v in a.iteritems()]
will get you [ ('a', 1), ('b', 2), ('c', 3) ] and
[(v,k) for k,v in a.iteritems()]
the other example.
Read more about list comprehensions if you like, it's very interesting what you can do with them.
Create a list of namedtuples
It can often be very handy to use namedtuple. For example, you have a dictionary of 'name' as keys and 'score' as values like:
d = {'John':5, 'Alex':10, 'Richard': 7}
You can list the items as tuples, sorted if you like, and get the name and score of, let's say the player with the highest score (index=0) very Pythonically like this:
>>> player = best[0]
>>> player.name
'Alex'
>>> player.score
10
How to do this:
list in random order or keeping order of collections.OrderedDict:
import collections
Player = collections.namedtuple('Player', 'name score')
players = list(Player(*item) for item in d.items())
in order, sorted by value ('score'):
import collections
Player = collections.namedtuple('Player', 'score name')
sorted with lowest score first:
worst = sorted(Player(v,k) for (k,v) in d.items())
sorted with highest score first:
best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)
[(k,v) for (k,v) in d.iteritems()]
and
[(v,k) for (k,v) in d.iteritems()]
What you want is dict's items() and iteritems() methods. items returns a list of (key,value) tuples. Since tuples are immutable, they can't be reversed. Thus, you have to iterate the items and create new tuples to get the reversed (value,key) tuples. For iteration, iteritems is preferable since it uses a generator to produce the (key,value) tuples rather than having to keep the entire list in memory.
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = { 'a': 1, 'b': 2, 'c': 3 }
>>> a.items()
[('a', 1), ('c', 3), ('b', 2)]
>>> [(v,k) for (k,v) in a.iteritems()]
[(1, 'a'), (3, 'c'), (2, 'b')]
>>>
These are the breaking changes from Python 3.x and Python 2.x
For Python3.x use
dictlist = []
for key, value in dict.items():
temp = [key,value]
dictlist.append(temp)
For Python 2.7 use
dictlist = []
for key, value in dict.iteritems():
temp = [key,value]
dictlist.append(temp)
>>> a={ 'a': 1, 'b': 2, 'c': 3 }
>>> [(x,a[x]) for x in a.keys() ]
[('a', 1), ('c', 3), ('b', 2)]
>>> [(a[x],x) for x in a.keys() ]
[(1, 'a'), (3, 'c'), (2, 'b')]
By keys() and values() methods of dictionary and zip.
zip will return a list of tuples which acts like an ordered dictionary.
Demo:
>>> d = { 'a': 1, 'b': 2, 'c': 3 }
>>> zip(d.keys(), d.values())
[('a', 1), ('c', 3), ('b', 2)]
>>> zip(d.values(), d.keys())
[(1, 'a'), (3, 'c'), (2, 'b')]
A alternative one would be
list(dictionary.items()) # list of (key, value) tuples
list(zip(dictionary.values(), dictionary.keys())) # list of (value, key) tuples
d = {'John':5, 'Alex':10, 'Richard': 7}
list = []
for i in d:
k = (i,d[i])
list.append(k)
print list
Python3 dict.values() not return a list. This is the example
mydict = {
"a": {"a1": 1, "a2": 2},
"b": {"b1": 11, "b2": 22}
}
print(mydict.values())
> output: dict_values([{'a1': 1, 'a2': 2}, {'b1': 11, 'b2': 22}])
print(type(mydict.values()))
> output: <class 'dict_values'>
print(list(mydict.values()))
> output: [{'a1': 1, 'a2': 2}, {'b1': 11, 'b2': 22}]
print(type(list(mydict.values())))
> output: <class 'list'>
x = {'a': 1, 'b': 2, 'c': 4, 'd':3}
sorted(map(lambda x : (x[1],x[0]),x.items()),key=lambda x : x[0])
Lets break the above code into steps
step1 = map(lambda x : (x[1],x[0]),x.items())
x[1] : Value
x[0] : Key
Step1 will create a list of tuples containing pairs in the form of (value,key) e.g. (4,'c')
step2 = sorted(step1,key=lambda x : x[0])
Step2 take the input of from Step 1 and sort using the 1st value of the tuple