I have a data structure as follows:
[(a,x1,1),(a,x2,5),(b,x1,1) ...]
and i want to turn it into a nested dictionary of the form
{a:{x1:1, x2:5}, b:{x1:1}...}
I tried
dictdata = {}
for row in rows:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
dictdata[ean]={} # init sub dictionary
dictdata[ean][period] = value
but every time I do dictdata[ean]={}, the contents get erased, so this will not work. If I do not initialise the sub-dictionary, I also cannot get it to work.
Any help appreciated
This is the kind of problem collections.defaultdict was built to solve:
https://docs.python.org/2/library/collections.html#collections.defaultdict
from collections import defaultdict
dictdata = defaultdict(dict)
rows = [('a','x1',1),('a','x2',5),('b','x1',1) ]
for row in rows:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
dictdata[period][ean] = value
dictdata
returns
{'a': {'x2': 5, 'x1': 1}, 'b': {'x1': 1}}
You can do it in one statement
rows = [('a','x1',1),('a','x2',5),('b','x1',1)]
result = dict()
for key1, key2, value in rows:
result.setdefault(key1, {}).update({key2: value})
Same thing but using defaultdict
from collections import defaultdict
rows = [("a", "x1", 1), ("a", "x2", 5), ("b", "x1", 1)]
d = defaultdict(dict)
for k, v, v2 in rows:
d[k][v] = v2
As a fix to your code, the proper way is to always if you have already the dictionary created, if not then instantiate one, like so:
>>> l
[('a', 'x1', 1), ('a', 'x2', 5), ('b', 'x1', 1)]
>>> d = {}
>>> for row in l:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
if period not in d:
d[period] = {}
if ean not in d[period]:
d[period][ean] = {}
d[period][ean] = value
>>> d
{'a': {b'x1': 1, b'x2': 5}, 'b': {b'x1': 1}}
You can also do it with defaultdict from collections, very straight forward:
>>> l = [('a','x1',1),('a','x2',5),('b','x1',1)]
>>>
>>> from collections import defaultdict
>>>
>>>
>>> d = defaultdict(dict)
>>>
>>> for k, k_sub, v in l:
d[k][k_sub] = v
>>> d
defaultdict(<class 'dict'>, {'a': {'x1': 1, 'x2': 5}, 'b': {'x1': 1}})
Solution for an arbitrary length of tuples:
l = [('a', 'x1', 1), ('a', 'x2', 5), ('b', 'x1', 1), ('a', 'x3', 'y1', 'z1', 7), ('a', 'x3', 'y1', 'z2', 666)]
def f(data):
def _f(store, keys, value):
if len(keys) == 1:
return {keys[0]: value}
store[keys[0]].update(_f(defaultdict(dict), keys[1:], value))
return store
result = defaultdict(dict)
for a in data:
_f(result, a[:-1], a[-1])
return dict(result)
print(f(l))
{'a': {'x1': 1, 'x2': 5, 'x3': {'y1': {'z2': 666}}}, 'b': {'x1': 1}}
Related
The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.
To put the code :
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
finalDict = defaultdict(int)
for eachItem in listOfItems:
for key, val in eachItem:
finalDict[key] += val
print(finalDict)
This is giving me what I want : defaultdict(<class 'int'>, {'a': 7, 'b': 5, 'c': 0, 'd': 5}) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :
finalDict = defaultdict(int)
finalDict = {key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem}
print(finalDict)
But the output is : {'a': 6, 'b': 2, 'c': 0, 'd': 5} What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?
Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:
>>> from collections import Counter
>>> c = Counter()
>>> for eachItem in listOfItems:
... c.update(dict(eachItem))
...
>>> c
Counter({'a': 7, 'b': 5, 'd': 5, 'c': 0})
This is because you do not assign any value to your finalDict inside your dict in comprehension.
In your dict in comprehension you are literally changing the type of finalDict
As far as I know you cannot assign value to your dict inside a dict in comprehension.
Here is a way to get the dictionnary you want
from functools import reduce
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
list_dict = [{key: val} for eachItem in listOfItems for key, val in eachItem]
def sum_dict(x, y):
return {k: x.get(k, 0) + y.get(k, 0) for k in set(x) | set(y)}
print(reduce(sum_dict, list_dict))
Simple solution without using additional modules:
inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
l = [item for sublist in inp_list for item in sublist] # flatten the list
sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]
print(sums)
trying to use python's built-in methods instead of coding the functionality myself:
The long and explained solution
from itertools import chain, groupby
from operator import itemgetter
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
# just flat the list of lists into 1 list..
flatten_list = chain(*listOfItems)
# get all elements grouped by the key, e.g 'a', 'b' etc..
first = itemgetter(0)
groupedByKey = groupby(sorted(flatten_list, key=first), key=first))
#sum
summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)
# create a dict
d = dict(summed_by_key)
print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}
~one line solution
from itertools import chain, groupby
from operator import itemgetter
first = itemgetter(0)
d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))
print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}
I need to convert the above list of tuples to nested dictionary without overwriting the value as below in python
[('a', '1'),
('b', 'true'),
('b', 'none'),
('a', '2'),
('b', 'true'),
('a', '3'),
('b', 'false')]
{'a': {'1' : { 'b' : ('true','none')},
'2' : { 'b' : ('true')},
'3' : { 'b' : ('false')}}}
Converting each tuple into dictionary using
dict()
and merging the dictionary doesn't work. Is there any pythonic way to do this?
Here's one way to do it with collections.defaultdict:
from collections import defaultdict
import pprint
data = [('a', '1'), ('b', 'true'), ('b', 'none'), ('a', '2'), ('b', 'true'), ('a', '3'), ('b', 'false')]
d = defaultdict(lambda: defaultdict(lambda: defaultdict(tuple)))
for i, j in data:
if i == 'a':
p = d[i][j]
else:
p[i] += j,
pprint.pprint(d)
# {'a': {'1': defaultdict(<class 'tuple'>, {'b': ('true', 'none')}),
# '2': defaultdict(<class 'tuple'>, {'b': ('true',)}),
# '3': defaultdict(<class 'tuple'>, {'b': ('false',)})}}
You could also use the dictionary's setdefault method to return default values for new keys, although the defaultdict approach is much cleaner and faster:
c = {}
for i, j in data:
if i == 'a':
q = c.setdefault(i, {}).setdefault(j, {})
else:
q[i] = q.setdefault(i, ()) + (j,)
pprint.pprint(c)
# {'a': {'1': {'b': ('true', 'none')},
# '2': {'b': ('true',)},
# '3': {'b': ('false',)}}}
Expanding #MosesKoledoye answer, if the first value in the dictionary is only 'a' and 'b', you know that the outer dictionary will always contain at most one element using 'a' as the key and the inner dictionary will always contain at most one element using 'b' as the key. So in the end you get the same information if it is {'1': ('true', 'none')…. You can convert that to your format simply by wrapping the data in some dictionaries. This means you can do the following
output = defaultdict(tuple)
for i, j in data:
if i == 'a':
current = j
else:
# i == 'b'
output[current] += (j, )
This will result in the following:
defaultdict(<type 'tuple'>, {'1': ('true', 'none'), '3': ('false',), '2': ('true',)})
Now to get it into a dictionary like yours you can do the following:
output = {k: {'b': v} for k, v in output.items()}
if output:
output = {'a': output}
Resulting in the following:
{'a': {'1': {'b': ('true', 'none')}, '3': {'b': ('false',)}, '2': {'b': ('true',)}}}
I have a following dictionary:
d1 = {}
I need to assign it the following values, but only the first n values from the following list:
all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
Final output: d1={"A":[1,1],"B":[2,1]}
1st version of the Question:
I have a following dictionary:
d1 = {'UID': 'A12B4', 'name': 'John', 'email': 'hi#example.com'}
How do I create a dictionary d2 such that d2 has the first n number of keys and values from d1?
2nd version of the Question
I have a following dictionary:
d1 = {}
I need to assign it the following values, but only the first n values from the following list:
all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
How do I create a dictionary d2 such that d2 has the first n number of keys and values from d1?
I'm sorry to tell you, but you shouldn't do that. At least, not with the stock dict. The reason is that no order is guaranteed in a dict, and whenever you'll add or remove a value, the order of the dict CAN change.
But if you really insist you could do:
>>> d1 = {1:'a', 3:'b', 2:'c', 4:'d'}
>>> d1
{1: 'a', 2: 'c', 3: 'b', 4: 'd'}
>>> d.keys()[:2]
[1, 2]
>>> {k : d[k] for k in d.keys()[:2]}
{1: 'a', 2: 'c'}
but my suggestion to you is to use an OrderedDict object, that will guarantee the order of the elements within the dict:
>>> od = OrderedDict()
>>> od[1] = 'a'
>>> od[3] = 'b'
>>> od[2] = 'c'
>>> od[4] = 'd'
>>> od
OrderedDict([(1, 'a'), (3, 'b'), (2, 'c'), (4, 'd')])
>>> od.keys()[:2]
[1, 3]
>>> OrderedDict([(k, od[k]) for k in od.keys()[:2]])
OrderedDict([(1, 'a'), (3, 'b')])
Ok, looks like you just changed radically your question, so here's the new answer:
>>> all_examples= ['A,1,1', 'B,2,1', 'C,4,4', 'D,4,5']
>>> n = 2
>>> all_examples[:n]
['A,1,1', 'B,2,1']
here's how you select up to n values of a list.
once again, you're changing your question…
Final output: d1={"A":[1,1],"B":[2,1]}
well you can just do:
>>> {elt[0] : (elt[1], elt[2]) for elt in [elt.split(',') for elt in all_examples[:n]]}
{'A': ('1', '1'), 'B': ('2', '1')}
HTH
I have a list as a input made from tuples where the origin is the 1st object and the neighbour is the 2nd object of the tuple.
for example :
inp : lst = [('a','b'),('b','a'),('c',''),('a','c')]
out : {'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}
first i tried to cast the list into a dictonary,
like this
dictonary = dict(lst)
but i got an error say that
dictionary update sequence element #0 has length 1; 2 is required
The simplest is probably inside a try / except block:
lst = [('a','b'),('b','a'),('c',''),('a','c')]
out = dict()
for k, v in lst:
try:
if v != '':
out[k][1].append(v)
else:
out[k][1].append([])
except KeyError:
if v != '':
out[k] = (k, [v])
else:
out[k] = (k, [])
print out
Which gives:
{'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}
Here's how I did it, gets the result you want, you can blend the two operations into the same loop, make a function out of it etc, have fun! Written without Python one liners kung-fu for beginner friendliness!
>>> lst = [('a','b'),('b','a'),('c',''),('a','c')]
>>> out = {}
>>> for pair in lst:
... if pair[0] not in out:
... out[pair[0]] = (pair[0], [])
...
>>> out
{'a': ('a', []), 'c': ('c', []), 'b': ('b', [])}
>>> for pair in lst:
... out[pair[0]][1].append(pair[1])
...
>>> out
{'a': ('a', ['b', 'c']), 'c': ('c', ['']), 'b': ('b', ['a'])}
Just here to mention setdefault
lst = [('a','b'),('b','a'),('c',''),('a','c')]
d = {}
for first, second in lst:
tup = d.setdefault(first, (first, []))
if second and second not in tup[1]:
tup[1].append(second)
I'm new to this site, and I have a problem that I need some help with. I am trying to find the highest integer value in a dictionary and the corresponding key and then check if there are other keys with the same value. If there are duplicate values i want to randomly select one of them and return it. As of now the code can find the highest value in the dictionary and return the key, but it returns the same key each time. I'm not able to check for other keys with the same value.
def lvl2():
global aiMove2
posValueD = {}
for x in moveList(): #Movelist returns a list of tuples
m = aiFlip(x) #aiFlip returns an integer
posValueD[x] = m
aiMove2 = max(posValueD, key = posValueD.get)
return aiMove2
After getting the maximum, you can check each key of their values. This comprehension list returns a list of keys where the value associated if the same as aiMove2.
keys = [x for x,y in posValueD.items() if y == posValueD[aiMove2]]
Here's an example in Python shell:
>>> a = {'a':1, 'b':2, 'c':2}
>>> [x for x,y in a.items() if y == 2]
['c', 'b']
You could write something like this:
max_value = 0
max_keys = []
for key,value in myDict.iteritems():
if value > max_value:
max_value = value
max_keys = [key]
elif value == max_value:
max_keys.append(key)
if max_keys:
return random.choice(max_keys)
return None
You could use itertools groupby:
from itertools import groupby
di={'e': 0, 'd': 1, 'g': 2, 'f': 0, 'a': 1, 'c': 3, 'b': 2, 'l': 2, 'i': 1, 'h': 3, 'k': 0, 'j': 1}
groups=[]
for k, g in groupby(sorted(di.items(), key=lambda t: (-t[1], t[0])), lambda t: t[1]):
groups.append(list(g))
print(groups)
# [[('c', 3), ('h', 3)],
[('b', 2), ('g', 2), ('l', 2)],
[('a', 1), ('d', 1), ('i', 1), ('j', 1)],
[('e', 0), ('f', 0), ('k', 0)]]
Or, more succinctly:
print([list(g) for k, g in groupby(
sorted(di.items(), key=lambda t: (-t[1], t[0])),
lambda t: t[1])])
Then just take the first list in the groups list of lists.