I've got two dictionaries:
dict1 = {'id': 1001, 'text': 'some text 1', 'key1': 11, 'key2': 12}
dict2 = {'id': 1002, 'text': 'some text 2', 'key1': 1, 'key2': 2}
And I want to get something like this, keep 'id' from' dict1 and subtract 'key1' and 'key2':
dict3 = {'id': 1001, 'key1': 10, 'key2': 10 }
I've tried as following:
dict3 = {key: dict1[key] - dict2.get(key, 0) for key in ['key1', 'key2']}
but I don't know how to keep original 'id'.
Your code is fine but I would use the dict-comprehension to update the dict and not create it. That way, I could apply it to a dict that is already initialized with the desired 'id' value.
dict1 = {'id': 1001, 'text': 'some text 1', 'key1': 11, 'key2': 12}
dict2 = {'id': 1002, 'text': 'some text 2', 'key1': 1, 'key2': 2}
dict3 = {'id': dict1['id']} # initialize it first
dict3.update({key: dict1[key] - dict2.get(key, 0) for key in ['key1', 'key2']})
print(dict3) # {'id': 1001, 'key1': 10, 'key2': 10}
Since you have only two dicts with few element, its far more easier getting your required dict manually.
>>> d3 = { 'id':dict1['id'] , 'key1':dict1['key1']-dict2['key1'] ,
'key2':dict1['key2']-dict2['key2'] }
>>> d3
=> {'id': 1001, 'key1': 10, 'key2': 10}
Related
Suppose I have two list of dicts:
dict_list1 = [{'id': 'id1', 'sub_id': 'sub_id1', 'key1': 'value1'},
{'id': 'id2', 'sub_id': 'sub_id2', 'key3': 'value3'}]
dict_list2 = [{'id': 'id1', 'sub_id': 'sub_id1', 'key2': 'value2'},
{'id': 'id2', 'sub_id': 'sub_id2', 'key4': 'value4'}]
I want to merge them so that dictionaries with the same 'id' and 'sub_id' merges, becoming like this:
final_list=[{'id': 'id1', 'sub_id': 'sub_id1', 'key1': 'value1', 'key2': 'value2'},
{'id': 'id2', 'sub_id': 'sub_id2', 'key3': 'value3', 'key4': 'value4'}]
Right now I'm doing like this:
final_list = []
for dict1 in dict_list1:
for dict2 in dict_list2:
if attrs['id'] == seats['id'] and \
attrs['sub_id'] == seats['sub_id']:
final_list.append({**dict1, **dict2})
break
But it looks really bad. Is there a better/faster way to do it?
You can use defaultdict here. Use itertools.chain to chain both the dict lists or you just do final=dict1+dict2 but I prefer using chain.
from collections import defaultdict
from itertools import chain
dict_list1 = [{'id': 'id1', 'sub_id': 'sub_id1', 'key1': 'value1'},
{'id': 'id2', 'sub_id': 'sub_id2', 'key3': 'value3'}]
dict_list2 = [{'id': 'id1', 'sub_id': 'sub_id1', 'key2': 'value2'},
{'id': 'id2', 'sub_id': 'sub_id2', 'key4': 'value4'}]
final=chain(dict_list1,dict_list2) #You can just do final=dict_list1+dict_list2
out=defaultdict(dict)
for d in final:
k=(d['id'],d['sub_id'])
out[k].update(d)
list(out.values())
# [{'id': 'id1', 'sub_id': 'sub_id1', 'key1': 'value1', 'key2': 'value2'},
# {'id': 'id2', 'sub_id': 'sub_id2', 'key3': 'value3', 'key4': 'value4'}]
I have a list of nested dictionaries:
[{'a': 1,
'b': 'string',
'c': [{'key1': 80,
'key2': 'string',
'key3': 4033},
{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1}]},
{'a': 1,
'b': 'string',
'c': [{'key1': 80,
'key2': 'string',
'key3': 4033},
{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1,
'key5': 2}]}]
Please not that the values of key c is a list of dictionaries again.
Now I want to filter out from this list all dictionaries with key c, that do not contain key1, key2, key3 & key4.
I thought of looping first over the first, second, and so on dict in the list, and then looping over the nested dicts that have c as a key. Then, if the dict inside c does not meet my requirement, I delete it.
Therefore my code would be:
for j in range(len(mydict)):
for i in range(len(mydict[j]["c"])):
if not all (k in mydict[j]["c"][i] for k in ("key1", "key2", "key3", "key4")):
del(mydict[j]["c"][i])
But I am getting a IndexError: list index out of range error. Where is my mistake?
My desired output would be:
[{'a': 1,
'b': 'string',
'c': [{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1}]},
{'a': 1,
'b': 'string',
'c': [{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1,
'key5': 2}]}]
The problem is that with for i in range(len(mydict[j]["c"])): you are iterating the lists in the dict while at the same time removing from those lists. Instead, you can replace the inner loop with a list comprehension:
for d in mydict:
d['c'] = [d2 for d2 in d['c']
if all(k in d2 for k in ("key1", "key2", "key3", "key4"))]
Just to have another option:
keep = {'key1', 'key2', 'key3', 'key4'}
for h in mydict:
h['c'] = [ e for e in h['c'] if len(keep - set(e.keys())) == 0 ]
If you wanted another perspective on it:
def remove_keys(mydict):
mydict2 = mydict
keys = ['key1', 'key2', 'key3', 'key4']
for xIndex, x in enumerate(mydict):
for yIndex, y in enumerate(x['c']):
if not all(key in y.keys() for key in keys):
del mydict2[xIndex]['c'][yIndex]
return mydict2
Returns a new dictionary with the modifications.
What I can do:
dict1 = {'key1':0, 'key2':10, 'key3':110}
dict2 = dict(dict1)
for key in dict2:
dict2[key] = 0
print(dict2) # {'key1':0, 'key2':0, 'key3':0}
Is there a simple way to do that?
Simplest, using dict comprehension :
>>> {k:0 for k in dict1}
# driver values :
IN : dict1 = {'key1':0, 'key2':10, 'key3':110}
OUT : {'key1':0, 'key2':0, 'key3':0}
Yes. Use dict.fromkeys:
>>> dict1 = {'key1':0, 'key2':10, 'key3':110}
>>> dict.fromkeys(dict1, 0)
{'key1': 0, 'key2': 0, 'key3': 0}
Be careful, though, if your fill-value is a mutable object, this will mean every value will be the same instance of that mutable object, e.g.:
>>> new_dict = dict.fromkeys(dict1, [])
>>> new_dict
{'key1': [], 'key2': [], 'key3': []}
>>> new_dict['key1'].append('foo')
>>> new_dict
{'key1': ['foo'], 'key2': ['foo'], 'key3': ['foo']}
dict1 = {'key1':0, 'key2':10, 'key3':110}
dict2 = dict((i,0) for i in dict1)
Result:
{'key3': 0, 'key2': 0, 'key1': 0}
I've got two nested dictionaries that have overlapping keys at the first level, but different keys at the second level. I want to merge them, so that the new dictionary has all of the keys.
A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
The result should be
A_B = {'id1': {'key1': 1, 'key2': 2, 'key3': 5}, 'id2':{'key1': 3, 'key2': 4, 'key3': 6}}
I know that I could do a for loop
for key in A:
A[key].update(B[key])
But I would like to know if there is a cleaner solution.
You could merge them in a dictionary comprehension:
A_B = {k: dict(A.get(k, {}), **B.get(k, {})) for k in A.viewkeys() | B.viewkeys()}
This uses the Python 2 dictionary keys view object; in Python 3, use dict.keys() instead of dict.viewkeys().
This'll merge all keys even if they are only present in one or the other of the dictionaries.
Demo with your input:
>>> A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
>>> B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
>>> {k: dict(A.get(k, {}), **B.get(k, {})) for k in A.viewkeys() | B.viewkeys()}
{'id2': {'key3': 6, 'key2': 4, 'key1': 3}, 'id1': {'key3': 5, 'key2': 2, 'key1': 1}}
or with input with more varied keys:
>>> C = {'foo': {'spam': 1, 'ham': 2}, 'bar': {'spam': 43, 'eggs': 81}}
>>> D = {'baz': {'vikings': 'singing'}, 'bar': {'monty': 'python'}}
>>> {k: dict(C.get(k, {}), **D.get(k, {})) for k in C.viewkeys() | D.viewkeys()}
{'bar': {'eggs': 81, 'monty': 'python', 'spam': 43}, 'foo': {'ham': 2, 'spam': 1}, 'baz': {'vikings': 'singing'}}
Iterate dictionary B
Check if key from the B is present in the A- Exception Handling
If yes, then Update respective value of A by B.
If Not, then Add New Key with value in A
code:
>>> A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
>>> B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
>>> for i, j in B.items():
... if i in A:
... A[i].update(j)
... else:
... A[i] = j
...
>>> A
{'id2': {'key3': 6, 'key2': 4, 'key1': 3}, 'id1': {'key3': 5, 'key2': 2, 'key1': 1}}
>>>
i need to create a dictionary from a large list of dict, removing all the duplicate dicts
the input list is something like:
input = [{'id': 1, 'value1': 'value1', 'value2': 'value2'},{'id': 2, 'value1': 'value1', 'value2': 'value2'}, {'id': 2, 'value1': 'value1', 'value3': 'value4'}]
and i want to create a dictionary like this, using "id" value as key for the new dict:
output = {
1: [{'id': 1, 'value1': 'value1', 'value2': 'value2'}]
2: [{'id': 2, 'value1': 'value1', 'value2': 'value2'}, {'id': 2, 'value1': 'value1', 'value3': 'value4'}]
}
my first try was:
output = {}
for el in input:
if el['id'] not in output or el not in output[el['id']]:
output.setdefault(el['id'], []).append(el)
and it actually works but it's super slow, len(input) is roughly 20k/30k items
is there any other way to do this a little bit faster?
thanks!
Use a separate set to track of seen dictionaries; you'll have to convert them to hashable representations first:
seen = set()
drepr = lambda d: tuple(sorted(d.items()))
output = {}
for el in input:
if drepr(el) not in seen:
output.setdefault(el['id'], []).append(el)
seen.add(drepr(el))
You can speed it up a little by using a collections.defaultdict object as that'll materialize lists without having to look up a method and push a stack frame to call it:
from collections import defaultdict
seen = set()
drepr = lambda d: tuple(sorted(d.items()))
output = defaultdict(list)
for el in input:
if drepr(el) not in seen:
output[el['id']].append(el)
seen.add(drepr(el))
Demo:
>>> input = [{'id': 1, 'value1': 'value1', 'value2': 'value2'},{'id': 2, 'value1': 'value1', 'value2': 'value2'}, {'id': 2, 'value1': 'value1', 'value3': 'value4'}]
>>> seen = set()
>>> drepr = lambda d: tuple(sorted(d.items()))
>>> output = {}
>>> for el in input:
... if drepr(el) not in seen:
... output.setdefault(el['id'], []).append(el)
... seen.add(drepr(el))
...
>>> from pprint import pprint
>>> pprint(output)
{1: [{'id': 1, 'value1': 'value1', 'value2': 'value2'}],
2: [{'id': 2, 'value1': 'value1', 'value2': 'value2'},
{'id': 2, 'value1': 'value1', 'value3': 'value4'}]}
Create a new output list with the duplicate dicts and then make each element in the new list a unique set of dicts
input=[{'id': 1, 'value1': 'value1', 'value2': 'value2'}, {'id': 2, 'value1': 'value1', 'value2': 'value2'}, {'value3': 'value4', 'id': 2, 'value1': 'value1'}, {'id': 2, 'value1': 'value1', 'value2': 'value2'}]
output={}
for el in input: output.setdefault(el['id'], []).append(el)
for key in output:
output[key]=map(dict, set(tuple(sorted(d.items())) for d in output[key]))
print output
[{'id': 2, 'value1': 'value1', 'value2': 'value2'}, {'value3': 'value4', 'id': 2, 'value1': 'value1'}]