Related
This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed last month.
here's my code:
import copy
teamdict = {1:{},2:{},3:{},4:{},5:{}}
teamlst = []
matchlst = [1,2,3,4,5]
lst = [[1,5,0],[1,0,3],[2,3,0],[2,0,1],[3,0,6],[3,0,1],[4,0,1],[4,0,5],[5,0,8]]
for i in matchlst:
for j in lst:
if i == j[0]:
teamlst.append(j[2])
elif len(teamlst)>0 and i != j:
continue
else:
pass
teamlst = set(teamlst)
teamlst = list(teamlst)
teamlst.sort()
team_dictionary = dict.fromkeys(teamlst, [])
teamdict[i] = team_dictionary
teamlst.clear()
print(teamdict)
dic = copy.deepcopy(teamdict)
for i in lst:
dic[i[0]][i[2]].append(i[1])
print(dic)
this is what i got:
{1: {0: [5, 0], 3: [5, 0]}, 2: {0: [3, 0], 1: [3, 0]}, 3: {1: [0, 0], 6: [0, 0]}, 4: {1: [0, 0], 5: [0, 0]}, 5: {8: [0]}}
but what i expect is:
{1: {0: [5], 3: [0]}, 2: {0: [3], 1: [0]}, 3: {1: [0], 6: [0]}, 4: {1: [0], 5: [0]}, 5: {8: [0]}}
what goes wrong?
seems like this append method add the element to all the keys in the nested dictionary
I assume you have created your dictionary with multiple references to the same list.
If I execute your code I get what you want.
>>> lst = [[1,5,0],[1,0,3],[2,3,0],[2,0,1],[3,0,6],[3,0,1],[4,0,1],[4,0,5],[5,0,8]]
>>> dic = {1: {0: [], 3: []}, 2: {0: [], 1: []}, 3: {1: [], 6: []}, 4: {1: [], 5: []}, 5: {8: []}}
>>> for i in lst:
... dic[i[0]][i[2]].append(i[1])
...
>>> print(dic)
{1: {0: [5], 3: [0]}, 2: {0: [3], 1: [0]}, 3: {1: [0], 6: [0]}, 4: {1: [0], 5: [0]}, 5: {8: [0]}}
I have a dictionary, with integers as key (1 up to n), and values being lists (1 up to m elements). I would like to create a new dictionary, with the primary key being an integer (1 up to each n * m), and the secondary key the original n key with values as strings from the list.
Input:
input = {
1: ['foo', ...],
2: ['buz', ...],
3: ['sam', 'foo', ...],
4: ['bar', ...],
5: ['foo', 'bar', ...]
...
}
Where ... marks more values being present. Values are sometimes the same, sometimes not, and order is not important here even though I used lists.
Output: for this particular case (if ... omitted).
output = {
1: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'foo'},
2: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'bar'},
3: {1: 'foo', 2: 'buz', 3: 'bar', 4: 'bar', 5: 'foo'},
4: {1: 'foo', 2: 'buz', 3: 'bar', 4: 'bar', 5: 'bar'}
}
Edit: second example
input = {
1: ['alice'],
2: ['tom', 'josh'],
3: ['mike', 'adam'],
4: ['kate', 'filip'],
}
output = {
1: {1: 'alice', 2: 'tom', 3: 'mike', 4: 'kate'},
2: {1: 'alice', 2: 'tom', 3: 'mike', 4: 'filip'},
3: {1: 'alice', 2: 'tom', 3: 'adam', 4: 'kate'},
4: {1: 'alice', 2: 'tom', 3: 'adam', 4: 'filip'},
5: {1: 'alice', 2: 'josh', 3: 'mike', 4: 'kate'},
6: {1: 'alice', 2: 'josh', 3: 'mike', 4: 'filip'},
7: {1: 'alice', 2: 'josh', 3: 'adam', 4: 'kate'},
8: {1: 'alice', 2: 'josh', 3: 'adam', 4: 'filip'},
}
If someone has at least a hint I would very much appreciate it. Since I can't find the working solution at all.
Thanks all in advance
You can use itertools.product and a nested dictionary comprehension:
from itertools import product
out = {i+1: {j+1: e for j,e in enumerate(x)}
for i,x in enumerate(product(*data.values()))}
output:
{1: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'foo'},
2: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'bar'},
3: {1: 'foo', 2: 'buz', 3: 'foo', 4: 'bar', 5: 'foo'},
4: {1: 'foo', 2: 'buz', 3: 'foo', 4: 'bar', 5: 'bar'}}
Input:
data = {1: ['foo'], 2: ['buz'], 3: ['sam', 'foo'], 4: ['bar'], 5: ['foo', 'bar']}
d = {0: {0: {0: 0, 1: 0},
1: {0: 0,
2: np.array([ 0.02981036])}},
9: {0: {0: 0, 1: 0},
7: {0: 0,
4: np.array([ 0.01502996]),
9: 0},
8: {0: 0,
1: 0},
9: {0: 0, 1: 0}}}
The dictionary is above, what I want to is delete the keys of which the value is 0, and convert the array form to float. The wanted output is:
d = {0: {1: {2: 0.02981036}}, 9: {7: {4: 0.01502996}}}
I tried to use a for loop to delete the "0" items, but always got KeyError: 0. I am a newbie of python, please help me on board. Thanks!!
A recursive solution:
def func(d):
new_d = {} # create a new dict
if any(v != 0 for v in d.values()): # evaluate items if any `v != 0`
for k, v in d.items():
if type(v) == dict:
new_v = func(v)
if new_v: # do not create key if `func(v)` is an empty dict
new_d[k] = new_v
elif v != 0: # convert other non-zero values to float
new_d[k] = float(v) # place try/except here if you expect non-int values
return new_d
>>> func(d)
Out[]: {0: {1: {2: 0.02981036}}, 9: {7: {4: 0.01502996}}}
What you have here is dict or dict of dict. Using json may be a good idea. But here is a scratch version of solution.
Also, since you are trying to delete keys while iterating through the keys at various levels, you may run into RuntimError issue. For that purpose we will need to deepcopy the dict , iterate through original and delete from the copy.
SourceCode
import numpy as np
import copy
d = {0: {0: {0: 0, 1: 0},
1: {0: 0,
2: np.array([ 0.02981036])}},
9: {0: {0: 0, 1: 0},
7: {0: 0,
4: np.array([ 0.01502996]),
9: 0},
8: {0: 0,
1: 0},
9: {0: 0, 1: 0}}}
d2 = copy.deepcopy(d)
for k1,v1 in d.iteritems():
for k2,v2 in v1.iteritems():
for k3,v3 in v2.iteritems():
#print k1,k2,k3,v3
if v3 == 0:
d2[k1][k2].pop(k3)
if type(v3) is np.ndarray:
v3 = v3.tolist()
d2[k1][k2][k3] = float(''.join(str(i) for i in v3))
if len(d2[k1][k2]) == 0:
d2[k1].pop(k2)
>>> d2
{0: {1: {2: 0.02981036}}, 9: {7: {4: 0.01502996}}}
import numpy
def clean(d):
new = {}
for k, v in d.items():
if v == 0:
pass
elif isinstance(v, numpy.ndarray):
new_element = float(v[0])
new[k] = new_element
else:
new_element = clean(v)
if new_element != {}:
new[k] = new_element
return new
https://repl.it/MO9A/1
You can try this to remove all zeros which have value 0:
import numpy as np
from copy import deepcopy
d = {0: {0: {0: 0, 1: 0},
1: {0: 0,
2: np.array([ 0.02981036])}},
9: {0: {0: 0, 1: 0},
7: {0: 0,
4: np.array([ 0.01502996]),
9: 0},
8: {0: 0,
1: 0},
9: {0: 0, 1: 0}}}
deep_copy=deepcopy(d)
for key,value in d.items():
for key1,value1 in value.items():
for key2,value2 in value1.items():
if value2==0:
del deep_copy[key][key1][key2]
new_deep_copy=deepcopy(deep_copy)
for key,value in deep_copy.items():
for key1,value1 in value.items():
for key2,value2 in value1.items():
if isinstance(value2,np.ndarray):
new_deep_copy[key][key1][key2]=float(value2)
if value1=={}:
del new_deep_copy[key][key1]
print(new_deep_copy)
output:
{0: {1: {2: 36.0}}, 9: {7: {4: 0.01502996}}}
I have two dictionaries, and what I'm trying to do is a bit odd. Basically, I want to merge them. That's simple enough. But they're hierarchies of of dictionaries, and I want to merge them in such a way that if an item in a dictionary is itself a dictionary and exists in both, I want to merge those dictionaries as well. If it's not a dictionary, I want the values from the second dictionary to overwrite the values from the first one. Something sort of like this:
a = {0: {0: "a"},
1: [0, 1, 2]}
b = {0: {1: "b"},
1: [3, 4, 5]}
Merge(a, b)
#output:
{0: {0: "a",
1: "b"},
1: [3, 4, 5]}
Does that make sense? Because the key "0" contained a dictionary in both a and b, it merged those dictionaries as well. But in the case of the second key, it was a list so it just overwrote it.
So I suppose I'll be looking at some kind of recursive function? Not quite sure how to approach this one.
Thanks!
Edit: I forgot to mention one pretty crucial detail:
I need a function that works in both 2.6.2 and 2.7.3.
Assuming you might have nested dictionaries (based on your thinking in terms of recursion), something like this should work,
from copy import deepcopy
def merge(a, b):
if isinstance(b, dict) and isinstance(a, dict):
a_and_b = a.viewkeys() & b.viewkeys()
every_key = a.viewkeys() | b.viewkeys()
return {k: merge(a[k], b[k]) if k in a_and_b else
deepcopy(a[k] if k in a else b[k]) for k in every_key}
return deepcopy(b)
The return value of merge(a, b) is conceptually like creating a (deep) copy of a and running a recursive version of a.update(b).
Using some nested examples,
a = {0: {0: 'a'},
1: [0, 1, 2],
2: [9, 9],
3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}}
b = {0: {1: 'b'},
1: [3, 4, 5],
2: {22: 22, 33: 33},
3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}}
merge(a, b) produces,
{0: {0: 'a', 1: 'b'},
1: [3, 4, 5],
2: {22: 22, 33: 33},
3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}}
EDIT: Python 2.6 version
def merge(a, b):
if isinstance(b, dict) and isinstance(a, dict):
a_and_b = set(a).intersection(b)
every_key = set(a).union(b)
return dict((k, merge(a[k], b[k]) if k in a_and_b else
deepcopy(a[k] if k in a else b[k])) for k in every_key)
return deepcopy(b)
Hmm.. as long as you're not arbitrarily-nested, you don't need recursion.
from itertools import chain
{k:(v if not isinstance(v,dict) else dict(chain(a[k].items(), v.items()))) for k,v in b.items()}
Out[10]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}
(I'm using python 3 here, feel free to replace .items with .iteritems in python 2)
Since this is a bit verbose, there's always the sneaky way to merge two dicts:
{k:(v if not isinstance(v,dict) else dict(a[k], **v)) for k,v in b.items()}
Out[11]: {0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}
You may or may not want to use this syntax - though it is compact, it kind of abuses cPython implementation details.
Needed something similar and implemented a more straightforward recursive solution. In-place updates dict 'd'.
from Collections import MutableMapping
def merge(d, v):
"""
Merge two dictionaries.
Merge dict-like `v` into dict-like `d`. In case keys between them are the same, merge
their sub-dictionaries where possible. Otherwise, values in `v` overwrite `d`.
"""
for key in v:
if key in d and isinstance(d[key], MutableMapping) and isinstance(v[key], MutableMapping):
d[key] = merge(d[key], v[key])
else:
d[key] = v[key]
return d
Example 1:
a = {0: {0: "a"},
1: [0, 1, 2]}
b = {0: {1: "b"},
1: [3, 4, 5]}
>>> merge(a, b)
{0: {0: 'a', 1: 'b'}, 1: [3, 4, 5]}
Example 2:
a = {0: {0: 'a'},
1: [0, 1, 2],
2: [9, 9],
3: {'a': {1: 1, 2: 2}, 'b': [0, 1]}}
b = {0: {1: 'b'},
1: [3, 4, 5],
2: {22: 22, 33: 33},
3: {'a': {2: 22, 3: 33}, 'b': [99, 88]}}
>>> merge(a, b)
{0: {0: 'a', 1: 'b'},
1: [3, 4, 5],
2: {22: 22, 33: 33},
3: {'a': {1: 1, 2: 22, 3: 33}, 'b': [99, 88]}}
here response in an dictionary which is having form values stored in an dictionary. My output is generatd with seperate dictionary which i doesnot need seperately. I want all the elements in one dictionary only
resp = {}
b = []
for i in range(1, 10):
resp_i = form.getvalue('opt_%d' %i, '0')
resp[i] = int(resp_i)
arg = {i : resp[i]}
b.append(arg)
#print len(b)
for each in b:
print each
Actual Output: {1: 1} {2: 1} {3: 3} {4: 1} {5: 3} {6: 0} {7: 0} {8: 0} {9: 0}
Expected output: {1: 1, 2: 1, 3: 3, 4: 1, 5: 3, 6: 0, 7: 0, 8: 0, 9: 0}
the problem is here:
b = []
for ...
arg = {i: resp[i]} # creates a new dict
b.append(arg) # adds the dict to the list
What you're probably looking for is something like:
b = {}
for ...
b.update(arg)
Of course, this still isn't the cleanest way to do it. After all, why create all the temporary dictionaries?
b = {}
for ...
b[i] = resp[i]
would work, or you could probably even pull it all into a dictionary comprehension.
def form_getvalue(i):
return ('0', '1', '1', '3', '1', '3', '0', '0', '0', '0')[i]
resp = {}
for i in range(1, 10):
resp[i] = int(form_getvalue(i))
print 'resp=%s' % (resp,)
The output of the above is:
resp={1: 1, 2: 1, 3: 3, 4: 1, 5: 3, 6: 0, 7: 0, 8: 0, 9: 0}