addition of more than one dict in python - python

i have 6 dict like this
dict1
dict2
dict3
dict4
dict5
dict6
now I want all of this in one dict. so I used this
dict1.update({'dict2':dict2})
dict3.update({'dict1':dict1})
dict4.update({'dict4':dict3})
dict5.update({'dict5':dict4})
dict6.update({'dict6':dict5})
at last dict6 contains all value but it's not formatted correctly and it's not the pythonic way to do it
I want to improve this any suggestions
right now I'm getting like this but I don't want like this
{"main_responses": {"dict1": {"dict2": {"dict3": {"dict4": {"dict5": {}}}}}}}
i want
{"main_responses":{ "dict1": {dict1_values}, "dict2": {dict2_values}..... and so on

Try this:
from itertools import chain
d = chain.from_iterable(d.items() for d in (ada_dict,
wordpress_version_dict,
drupal_version_dict,
ssl_dict,
link_dict,
tag_dict))
api_response = {'api_response':d}
Or this, using reduce:
d = reduce(lambda x,y: dict(x, **y), (ada_dict,
wordpress_version_dict,
drupal_version_dict,
ssl_dict,
link_dict,
tag_dict))
api_response = {'api_response':d}

Giving a very similar example of my own based on your requirements:
>>> d1 = {'a':1}
>>> d2 = {'b':2}
>>> d3 = {'c':3}
>>> d4 = {'d':4}
#magic happens here
>>> d = {'d1':d1 , 'd2':d2, 'd3':d3, 'd4':d4}
>>> d
=> {'d1': {'a': 1}, 'd2': {'b': 2}, 'd3': {'c': 3}, 'd4': {'d': 4}}
Since you do not have all the dictionaries that you want added in one place, this is about as easy as it gets.
In case you want to add another key to your collection of all dictionaries (d here), do:
>>> out = {'api_responses': d}
#or in one step if you do not want to use `d`
>>> out = {'api_responses': {'d1':d1 , 'd2':d2, 'd3':d3, 'd4':d4}}
>>> out
=> {'api_responses': {'d1': {'a': 1}, 'd2': {'b': 2}, 'd3': {'c': 3}, 'd4': {'d': 4}}}

If you want add all dict in a single one "newDict", Be carrefull if several keys exist in multiple Dict :
ada_dict={'k1':'v1'}
wordpress_version_dict={'k2':'v2'}
drupal_version_dict={'k3':'v3'}
ssl_dict={'k4':'v4'}
link_dict={'k5':'v5'}
tag_dict={'k5':'v5'}
newDict={}
newDict.update( (k,v) for k,v in ada_dict.iteritems() if v is not None)
newDict.update( (k,v) for k,v in wordpress_version_dict.iteritems() if v is not None)
newDict.update( (k,v) for k,v in drupal_version_dict.iteritems() if v is not None)
newDict.update( (k,v) for k,v in ssl_dict.iteritems() if v is not None)
newDict.update( (k,v) for k,v in link_dict.iteritems() if v is not None)
newDict.update( (k,v) for k,v in tag_dict.iteritems() if v is not None)
print {'api_response':newDict}
https://repl.it/ND3p/1

please add more comment to your post, but as I see you need something like , is not it ?
>>> foo=lambda dest, src, tag: [dest.update({tag:i}) for i in src]
>>> x={1:1}
>>> y={2:2}
>>> foo(x, y, "tag")
[None]
>>> x
{1: 1, 'tag': 2}
>>> y
{2: 2}

Does this help in getting the output you want?
new_dict=dict(ada_dict.items()+wordpress_version_dict.items() +drupal_version_dict.items()+ssl_dict.items()+link_dict.items()+tag_dict.items())

a =[ada_dict,
wordpress_version_dict,
drupal_version_dict,
ssl_dict,
link_dict,
tag_dict]
c= {}
for i in a:
c.update({i:i})
print c
{'ada_dict': 'ada_dict',
'drupal_version_dict': 'drupal_version_dict',
'link_dict': 'link_dict',
'ssl_dict': 'ssl_dict',
'tag_dict': 'tag_dict',
'wordpress_version_dic': 'wordpress_version_dic'}
d={}
d.update({"api_responses":c})
print d
{'api_responses': {'ada_dict': 'ada_dict',
'drupal_version_dict': 'drupal_version_dict',
'link_dict': 'link_dict',
'ssl_dict': 'ssl_dict',
'tag_dict': 'tag_dict',
'wordpress_version_dic': 'wordpress_version_dic'}}

Related

Compare two dict and change keys in second if keys exists as sub-value in first

Need help remapping the keys for d2 if they match the value for id in d1. In case there are keys that are unmatched, drop them.
d1={'A':{'id':'a'},'B':{'id':'b'}}
d2={'a':1,'b':2, 'c':3}
Expected output:
{'A': 1, 'B': 2}
You could traverse d1 and use d2 as a lookup to modify values:
for k, d in d1.items():
d1[k] = d2.get(d['id'])
If you want to modify df2 instead, you could use a dict comprehension:
d2 = {k: d2.get(d['id']) for k, d in d1.items()}
or use two loops (once to modify values of keys that exist in df1 and once to remove any keys that don't exist in df1):
for k, d in d1.items():
d2[k] = d2.pop(d['id'])
for k in list(d2.keys() - d1.keys()):
d2.pop(k)
Output:
{'A': 123, 'B': 123}
This is probably what you're after
d1={'A':{'id':'a'},'B':{'id':'b'}}
d2={'a':123,'b':123}
for key, id_map in d1.copy().items(): # view over soft copy won't mutate
try:
d1[key] = d2[id_map["id"]]
except KeyError:
pass
>>> d1
{'A': 123, 'B': 123}
However, unmapped values will remain the same (ie if there is C, but no id in its mapping, or no c in d2..)
>>> d1={'A':{'id':'a'},'B':{'id':'b'},'C':{'id':'c'}}
[..]
>>> d1
{'A': 123, 'B': 123, 'C': {'id': 'c'}}
If you want to discard unmapped values, you could do so here with del d1[key] in the except or simply create a new dict to pack the keys and values into (never added if KeyError is raised)
Alternatively, if this is an error (ie. C must exist), you can simply let KeyError raise to the caller and have it deal with the consequences
As long as each 'val' appears at most once in d1's subdictionaries (i.e. the key: {'id': val} pairs in d1), you can iterate over d1's items like so:
d1 = {'A': {'id': 'a'}, 'B': {'id': 'b'}, 'C': {'id': 'c'}}
d2 = {'a': 123, 'b': 12, 'd': 8}
d3 = {k: d2[v['id']] for k, v in d1.items() if v['id'] in d2}
print(d3)
>>> {'A': 123, 'B': 12}
Since you need to check all key-value pairs in d1, this is the best you can do in terms of time and space efficiency.
However, if you will be 're-keying' many d2 dictionaries with the same d1, it may be faster to build a reverse-index to reuse:
reverse_mapping = {v['id']: k for k, v in d1.items()}
def rekey(dict_to_rekey, reverse_map):
return {reverse_map[k]: dict_to_rekey[k]
for k in dict_to_rekey.keys() & reverse_map.keys()}
d3 = rekey(d2, reverse_mapping)

Python convert dict of lists to dict of sets?

I have:
myDict = {'a': [1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
I want:
myDict = {'a': set([1,2,3]), 'b':set([4,5,6]), 'c':set([7,8,9])}
Is there a one-liner I can use to do this rather than looping through it and converting the type of the values?
You'll have to loop anyway:
{key: set(value) for key, value in yourData.items()}
If you're using Python 3.6+, you can also do this:
dict(zip(myDict.keys(), map(set, myDict.values())))
This can be done with map by mapping the values to type set
myDict = dict(map(lambda x: (x[0], set(x[1])), myDict.items()))
Or with either version of dictionary comprehension as well
myDict = {k: set(v) for k, v in myDict.items()}
myDict = {k: set(myDict[k]) for k in myDict}
You can use comprehension for it:
Basically, loop through the key-value pairs and create set out of each value for the corresponding key.
>>> myDict = {'a': [1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
>>> myDict = {k: set(v) for k, v in myDict.items()}
>>> myDict
{'a': {1, 2, 3}, 'b': {4, 5, 6}, 'c': {8, 9, 7}}
You can't do it without looping anyway, but you can have the looping done in one line, with the following code:
myDict = {k:set(v) for k, v in myDict.items()}
This is basically traversing each item in your dictionary and converting the lists to sets and combining the key(str):value(set) pairs to a new dictionary and assigning it back to myDict variable.

Accessing value which is nested inside 2 keys

Suppose I have the following dict:
L = {'A': {'root[1]': 'firstvalue', 'root[2]': 'secondvalue'}, 'B': {'root[3]': 'thirdvalue', 'root[4]': 'Fourthvalue'}}
How can I access the values of the keys root[1], root[2], root[3], root[4] (indexes of root[] is dynamic) in Python 2.7.
Try :
>>> L = {'A': {'root[1]': 'firstvalue', 'root[2]': 'secondvalue'}, 'B': {'root[3]': 'thirdvalue', 'root[4]': 'Fourthvalue'}}
>>> L['A']['root[1]']
'firstvalue'
>>> L['A']['root[2]']
'secondvalue'
>>> L['B']['root[3]']
'thirdvalue'
>>> L['B']['root[4]']
'Fourthvalue'
>>>
Something like this:
for (key, value) in L.items():
for (another_key, real_value) in value.items():
print(another_key, real_value)
To access the values from a dict nested inside the dict, i used the following step:
L = {'A': {'root[1]': 'firstvalue', 'root[2]': 'secondvalue'}, 'B': {'root[3]': 'thirdvalue', 'root[4]': 'Fourthvalue'}}
Solution:
F = {}
G = []
F = L.get("A", None)
F= {{'root[1]': 'firstvalue', 'root[2]': 'secondvalue'}}
for value in F.values():
G.append(value)
Output:
G = ['firstvalue', 'secondvalue']

Reconstruct dictionary in python

I have two dictionaries created from a config file:
dict1 = {'x':'A', 'y':'B', 'z':'C'} # decoding ABCs
dict2 = {'ID1': ('x','n1'), 'ID2': ('y','n2'), 'ID3':('z', 'n3') }
I want to create a new dictionary in the following format:
final = {'A':{'ID1':'n1', 'ID2':'n2'}, 'C':{'ID3':'n3'}, ...}
I did not come up with a clever way to do this. Does anyone have any ideas?
Consider:
final = {}
for id, (x, n) in dict2.items():
final.setdefault(dict1[x], {})[id] = n
which creates
{'A': {'ID2': 'n2', 'ID1': 'n1'}, 'C': {'ID3': 'n3'}}
Don't know if this meets your needs, but at least it's a valid structure.
Assuming x, y, z in dict2 and A, B, C in final:
final = {dict1[k]: {id: v} for id, (k, v) in dict2.items()}
In [6]: dict1 = {'x':'A', 'y':'B', 'z':'C'}
In [7]: dict2 = {'ID1': ('x','n1'), 'ID2': ('y','n2'), 'ID3':('z', 'n3') }
In [8]: {dict1[k]: {id: v} for id, (k, v) in dict2.items()}
Out[8]: {'A': {'ID1': 'n1'}, 'B': {'ID2': 'n2'}, 'C': {'ID3': 'n3'}}
If you really did mean there should be two As, then it cannot be expressed as a dict. Will a list of pairs do? You'll have to decide on an ordering then.
In [10]: [(dict1[k], {id: v}) for id, (k, v) in dict2.items()]
Out[10]: [('A', {'ID2': 'n2'}), ('C', {'ID3': 'n3'}), ('A', {'ID1': 'n1'})]

Merge several Python dictionaries [duplicate]

This question already has answers here:
How to merge dicts, collecting values from matching keys?
(17 answers)
Closed 3 months ago.
I have to merge list of python dictionary. For eg:
dicts[0] = {'a':1, 'b':2, 'c':3}
dicts[1] = {'a':1, 'd':2, 'c':'foo'}
dicts[2] = {'e':57,'c':3}
super_dict = {'a':[1], 'b':[2], 'c':[3,'foo'], 'd':[2], 'e':[57]}
I wrote the following code:
super_dict = {}
for d in dicts:
for k, v in d.items():
if super_dict.get(k) is None:
super_dict[k] = []
if v not in super_dict.get(k):
super_dict[k].append(v)
Can it be presented more elegantly / optimized?
Note
I found another question on SO but its about merging exactly 2 dictionaries.
You can iterate over the dictionaries directly -- no need to use range. The setdefault method of dict looks up a key, and returns the value if found. If not found, it returns a default, and also assigns that default to the key.
super_dict = {}
for d in dicts:
for k, v in d.iteritems(): # d.items() in Python 3+
super_dict.setdefault(k, []).append(v)
Also, you might consider using a defaultdict. This just automates setdefault by calling a function to return a default value when a key isn't found.
import collections
super_dict = collections.defaultdict(list)
for d in dicts:
for k, v in d.iteritems(): # d.items() in Python 3+
super_dict[k].append(v)
Also, as Sven Marnach astutely observed, you seem to want no duplication of values in your lists. In that case, set gets you what you want:
import collections
super_dict = collections.defaultdict(set)
for d in dicts:
for k, v in d.iteritems(): # d.items() in Python 3+
super_dict[k].add(v)
from collections import defaultdict
dicts = [{'a':1, 'b':2, 'c':3},
{'a':1, 'd':2, 'c':'foo'},
{'e':57, 'c':3} ]
super_dict = defaultdict(set) # uses set to avoid duplicates
for d in dicts:
for k, v in d.items(): # use d.iteritems() in python 2
super_dict[k].add(v)
you can use this behaviour of dict. (a bit elegant)
a = {'a':1, 'b':2, 'c':3}
b = {'d':1, 'e':2, 'f':3}
c = {1:1, 2:2, 3:3}
merge = {**a, **b, **c}
print(merge) # {'a': 1, 'b': 2, 'c': 3, 'd': 1, 'e': 2, 'f': 3, 1: 1, 2: 2, 3: 3}
and you are good to go :)
Merge the keys of all dicts, and for each key assemble the list of values:
super_dict = {}
for k in set(k for d in dicts for k in d):
super_dict[k] = [d[k] for d in dicts if k in d]
The expression set(k for d in dicts for k in d) builds a set of all unique keys of all dictionaries. For each of these unique keys, we use the list comprehension [d[k] for d in dicts if k in d] to build the list of values from all dicts for this key.
Since you only seem to one the unique value of each key, you might want to use sets instead:
super_dict = {}
for k in set(k for d in dicts for k in d):
super_dict[k] = set(d[k] for d in dicts if k in d)
It seems like most of the answers using comprehensions are not all that readable. In case any gets lost in the mess of answers above this might be helpful (although extremely late...). Just loop over the items of each dict and place them in a separate one.
super_dict = {key:val for d in dicts for key,val in d.items()}
When the value of the keys are in list:
from collections import defaultdict
dicts = [{'a':[1], 'b':[2], 'c':[3]},
{'a':[11], 'd':[2], 'c':['foo']},
{'e':[57], 'c':[3], "a": [1]} ]
super_dict = defaultdict(list) # uses set to avoid duplicates
for d in dicts:
for k, v in d.items(): # use d.iteritems() in python 2
super_dict[k] = list(set(super_dict[k] + v))
combined_dict = {}
for elem in super_dict.keys():
combined_dict[elem] = super_dict[elem]
combined_dict
## output: {'a': [1, 11], 'b': [2], 'c': [3, 'foo'], 'd': [2], 'e': [57]}
I have a very easy to go solution without any imports.
I use the dict.update() method.
But sadly it will overwrite, if same key appears in more than one dictionary, then the most recently merged dict's value will appear in the output.
dict1 = {'Name': 'Zara', 'Age': 7}
dict2 = {'Sex': 'female' }
dict3 = {'Status': 'single', 'Age': 27}
dict4 = {'Occupation':'nurse', 'Wage': 3000}
def mergedict(*args):
output = {}
for arg in args:
output.update(arg)
return output
print(mergedict(dict1, dict2, dict3, dict4))
The output is this:
{'Name': 'Zara', 'Age': 27, 'Sex': 'female', 'Status': 'single', 'Occupation': 'nurse', 'Wage': 3000}
Perhaps a more modern and concise approach for those who use python 3.3 or later versions is the use of ChainMap from the collections module.
from collections import ChainMap
d1 = {'a': 1, 'b': 3}
d2 = {'c': 2}
d3 = {'d': 7, 'a': 9}
d4 = {}
combo = dict(ChainMap(d1, d2, d3, d4))
# {'d': 7, 'a': 1, 'c': 2, 'b': 3}
For a larger collection of dict objects then star operator works
dict(ChainMap(*dict_collection))
Note that the resulting dictionary seems to only keep the value of the first key it encounters in the ordered collection and ignores any further duplicates.
This may be a bit more elegant:
super_dict = {}
for d in dicts:
for k, v in d.iteritems():
l=super_dict.setdefault(k,[])
if v not in l:
l.append(v)
UPDATE: made change suggested by Sven
UPDATE: changed to avoid duplicates (thanks Marcin and Steven)
Never forget that the standard libraries have a wealth of tools for dealing with dicts and iteration:
from itertools import chain
from collections import defaultdict
super_dict = defaultdict(list)
for k,v in chain.from_iterable(d.iteritems() for d in dicts):
if v not in super_dict[k]: super_dict[k].append(v)
Note that the if v not in super_dict[k] can be avoided by using defaultdict(set) as per Steven Rumbalski's answer.
If you assume that the keys in which you are interested are at the same nested level, you can recursively traverse each dictionary and create a new dictionary using that key, effectively merging them.
merged = {}
for d in dicts:
def walk(d,merge):
for key, item in d.items():
if isinstance(item, dict):
merge.setdefault(key, {})
walk(item, merge[key])
else:
merge.setdefault(key, [])
merge[key].append(item)
walk(d,merged)
For example, say you have the following dictionaries you want to merge.
dicts = [{'A': {'A1': {'FOO': [1,2,3]}}},
{'A': {'A1': {'A2': {'BOO': [4,5,6]}}}},
{'A': {'A1': {'FOO': [7,8]}}},
{'B': {'B1': {'COO': [9]}}},
{'B': {'B2': {'DOO': [10,11,12]}}},
{'C': {'C1': {'C2': {'POO':[13,14,15]}}}},
{'C': {'C1': {'ROO': [16,17]}}}]
Using the key at each level, you should get something like this:
{'A': {'A1': {'FOO': [[1, 2, 3], [7, 8]],
'A2': {'BOO': [[4, 5, 6]]}}},
'B': {'B1': {'COO': [[9]]},
'B2': {'DOO': [[10, 11, 12]]}},
'C': {'C1': {'C2': {'POO': [[13, 14, 15]]},
'ROO': [[16, 17]]}}}
Note: I assume the leaf at each branch is a list of some kind, but you can obviously change the logic to do whatever is necessary for your situation.
This is a more recent enhancement over the prior answer by ElbowPipe, using newer syntax introduced in Python 3.9 for merging dictionaries. Note that this answer does not merge conflicting values into a list!
> import functools
> import operator
> functools.reduce(operator.or_, [{0:1}, {2:3, 4:5}, {2:6}])
{0: 1, 2: 6, 4: 5}
For a oneliner, the following could be used:
{key: {d[key] for d in dicts if key in d} for key in {key for d in dicts for key in d}}
although readibility would benefit from naming the combined key set:
combined_key_set = {key for d in dicts for key in d}
super_dict = {key: {d[key] for d in dicts if key in d} for key in combined_key_set}
Elegance can be debated but personally I prefer comprehensions over for loops. :)
(The dictionary and set comprehensions are available in Python 2.7/3.1 and newer.)
python 3.x (reduce is builtin for python 2.x, so no need to import if in 2.x)
import operator
from functools import operator.add
a = [{'a': 1}, {'b': 2}, {'c': 3, 'd': 4}]
dict(reduce(operator.add, map(list,(map(dict.items, a))))
map(dict.items, a) # converts to list of key, value iterators
map(list, ... # converts to iterator equivalent of [[[a, 1]], [[b, 2]], [[c, 3],[d,4]]]
reduce(operator.add, ... # reduces the multiple list down to a single list
My solution is similar to #senderle proposed, but instead of for loop I used map
super_dict = defaultdict(set)
map(lambda y: map(lambda x: super_dict[x].add(y[x]), y), dicts)
The use of defaultdict is good, this also can be done with the use of itertools.groupby.
import itertools
# output all dict items, and sort them by key
dicts_ele = sorted( ( item for d in dicts for item in d.items() ), key = lambda x: x[0] )
# groups items by key
ele_groups = itertools.groupby( dicts_ele, key = lambda x: x[0] )
# iterates over groups and get item value
merged = { k: set( v[1] for v in grouped ) for k, grouped in ele_groups }
and obviously, you can merge this block of code into one-line style
merged = {
k: set( v[1] for v in grouped )
for k, grouped in (
itertools.groupby(
sorted(
( item for d in dicts for item in d.items() ),
key = lambda x: x[0]
),
key = lambda x: x[0]
)
)
}
I'm a bit late to the game but I did it in 2 lines with no dependencies beyond python itself:
flatten = lambda *c: (b for a in c for b in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))
o = reduce(lambda d1,d2: dict((k, list(flatten([d1.get(k), d2.get(k)]))) for k in set(d1.keys() + d2.keys())), dicts)
# output:
# {'a': [1, 1, None], 'c': [3, 'foo', 3], 'b': [2, None, None], 'e': [None, 57], 'd': [None, 2, None]}
Though if you don't care about nested lists, then:
o2 = reduce(lambda d1,d2: dict((k, [d1.get(k), d2.get(k)]) for k in set(d1.keys() + d2.keys())), dicts)
# output:
# {'a': [[1, 1], None], 'c': [[3, 'foo'], 3], 'b': [[2, None], None], 'e': [None, 57], 'd': [[None, 2], None]}

Categories

Resources