Get values from many dictionaries by hierarchy - python

I have 4 dictionaries, let's call them:
dict1 , dict2 , dict3 , dict4
Example:
dict1 = {'A': 1, 'B':2}
dict2 = {'A': 3, 'C':4}
dict3 = {'B': 5, 'D':6}
dict4 = {'A': 7, 'B':8, 'C': 9, 'D':10, 'E':11}
Each dictionary level is "stronger" than those who come after it. As in, A found in dict1 will be 'stronger' than A found in dict2 in terms of precedence.
Is there a short, elegant script to create a new dictionary, assembled from all four, where each key is taken from the "strongest" dictionary that contains that key?
The result should be: dict = {'A':1, 'B':2, 'C':4, 'D:6', 'E':11}

I think the easiest/clearest approach here would be to create a new dictionary then use its update method, which overwrites existing keys. Something like this makes the precedence pretty obvious:
>>> x = {}
>>> x.update(dict4)
>>> x.update(dict3)
>>> x.update(dict2)
>>> x.update(dict1)
>>> x
{'A': 1, 'B': 2, 'C': 4, 'D': 6, 'E': 11}
Docs
You could of course make a utility of some sort for this, something like:
>>> def collapse(*dicts):
... x = {}
... for dict in dicts:
... x.update(dict)
... return x
...
>>>
>>> collapse(dict4, dict3, dict2, dict1)
{'A': 1, 'B': 2, 'C': 4, 'D': 6, 'E': 11}
(Though you'd need to remember to pass the dictionaries in the correct order.)

You could do the following (works on python 3.5 and newer):
result = {**dict4, **dict3, **dict2, **dict1}

Here's a fairly simple way for an arbitrary number of dictionaries:
dict1 = {'A': 1, 'B':2}
dict2 = {'A': 3, 'C':4}
dict3 = {'B': 5, 'D':6}
dict4 = {'A': 7, 'B':8, 'C': 9, 'D':10, 'E':11}
# strongest dictionary last
dictionaries = [dict4, dict3, dict2, dict1]
dict(i for d in dictionaries for i in d.items())
Output:
{'A': 1, 'B': 2, 'C': 4, 'D': 6, 'E': 11}

You probably want a ChainMap, which is perfect for simulating scope.
>>> import collections
>>> cm = collections.ChainMap(dict1, dict2, dict3, dict4)
>>> dict(cm)
{'A': 1, 'B': 2, 'C': 4, 'D': 6, 'E': 11}
>>> cm['A'] = 'foo'
>>> cm
ChainMap({'A': 'foo', 'B': 2}, {'A': 3, 'C': 4}, {'B': 5, 'D': 6}, {'A': 7, 'B': 8, 'C': 9, 'D': 10, 'E': 11})
>>> dict1
{'A': 'foo', 'B': 2}

Related

Python. How to merge two dictionaries with the same keys?

I have two dicts:
a = {'a': 1, 'b': 2, 'c': 3}
b = {'a': 2, 'd': 4, 'c': 5}
and i want to get:
{'a': 2, 'b': 2, 'c': 5}
i used {**a, **b} but it return:
{'a': 2, 'b': 2, 'c': 5, 'd': 4}
Help me please exclude keys from b which not in a with the simplest and fastest way.
i have python 3.7
You have to filter the elements of the second dict first in order to not add any new elements. I got two possible solutions:
a = {'a': 1, 'b': 2, 'c': 3}
b = {'a': 2, 'd': 4, 'c': 5}
for k,v in b.items():
if (k in a.keys()):
a[k] = v
print(a)
a = {'a': 1, 'b': 2, 'c': 3}
b = {'a': 2, 'd': 4, 'c': 5}
a.update([(k,v) for k, v in b.items() if k in a.keys()])
print(a)
Output for both:
{'a': 2, 'b': 2, 'c': 5}
I think a comprehension is easy enough:
{ i : (b[i] if i in b else a[i]) for i in a }

How to reverse order of values but not keys in a python dictionnary?

What is the best way to reverse order of values but not keys in a python dictionnary ?
dictionnary = {'a': 3, 'b': 2, 'c': 1}
inversed_values = dictionnary.reverseValues()
print(inversed_values)
This should print out {'a': 1, 'b': 2, 'c': 3}
You can convert values to list then reverse them then create dict like below:
>>> dct = {'a': 3, 'b': 2, 'c': 1}
>>> dict(zip(dct.keys(),list(dct.values())[::-1]))
{'a': 1, 'b': 2, 'c': 3}

Return dictionary with one changed element

Let's say I have a list of dictionaries:
>>> d = [{'a': 2, 'b': 3, 'c': 4}, {'a': 5, 'b': 6, 'c': 7}]
And I want to perform a map operation where I change just one value in each dictionary. One possible way to do that is to create a new dictionary which simply contains the original values along with the changed ones:
>>> map(lambda x: {'a': x['a'], 'b': x['b'] + 1, 'c': x['c']}, d)
[{'a': 2, 'c': 4, 'b': 4}, {'a': 5, 'c': 7, 'b': 7}]
This can get unruly if the dictionaries have many items.
Another way might be to define a function which copies the original dictionary and only changes the desired values:
>>> def change_b(x):
... new_x = x.copy()
... new_x['b'] = x['b'] + 1
... return new_x
...
>>> map(change_b, d)
[{'a': 2, 'c': 4, 'b': 4}, {'a': 5, 'c': 7, 'b': 7}]
This, however, requires writing a separate function and loses the elegance of a lambda expression.
Is there a better way?
This works (and is compatible with python2 and python31):
>>> map(lambda x: dict(x, b=x['b']+1), d)
[{'a': 2, 'c': 4, 'b': 4}, {'a': 5, 'c': 7, 'b': 7}]
With that said, I think that more often than not, lambda based solutions are less elegant than non-lambda counterparts... The rational behind this statement is that I can immediately look at the non-lambda solution that you proposed and I know exactly what it does. The lambda based solution that I just wrote would take a bit of thinking to parse and then more thinking to actually understand...
1Though, map will give you an iterable object on python3.x that isn't a list...
First, writing a function doesn't seem that inelegant to me in the first place. That said, welcome to the brave new world of Python 3.5 and PEP 448:
>>> d = [{'a': 2, 'b': 3, 'c': 4}, {'a': 5, 'b': 6, 'c': 7}]
>>> d
[{'b': 3, 'a': 2, 'c': 4}, {'b': 6, 'a': 5, 'c': 7}]
>>> [{**x, 'b': x['b']+1} for x in d]
[{'b': 4, 'a': 2, 'c': 4}, {'b': 7, 'a': 5, 'c': 7}]
From how your map is behaving, it's clear you're using 2, but that's easy enough to fix. :-)
You can use a for loop with an update call. Here is a hacky one-liner:
dcts = [{'a': 2, 'b': 3, 'c': 4}, {'a': 5, 'b': 6, 'c': 7}]
dcts = [d.update({'b': d['b']+1}) or d for d in dcts]
Edit: To preserve original dicts:
from copy import copy
dcts = [d.update({'b': d['b']+1}) or d for d in map(copy, dcts)]

Convert list of lists to list of dictionaries

I want to convert a list of lists to a list of dictionaries. I have a way to do it but I suspect there's a better way:
t = [[1,2,3], [4,5,6]]
keys = ['a', 'b', 'c']
[{keys[0]:l[0], keys[1]:l[1], keys[2]:l[2]} for l in t]
with output
[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6, 'b': 5}]
This could be done with a loop, but I bet there's a function to do it even easier. From this answer I'm guessing there's a way to do it with the map command, but I'm not quite sure how.
You can use list comprehension with the dict() constructor and zip:
[dict(zip(keys, l)) for l in t ]
Demo
>>> d = [dict(zip(keys, l)) for l in t ]
>>>
>>> d
[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6, 'b': 5}]
>>>
It can also be solved with a dictionary comprehension, this way:
>>> [{k:v for k,v in zip(keys, l)} for l in t]
[{'c': 3, 'b': 2, 'a': 1}, {'c': 6, 'b': 5, 'a': 4}]

Merge Two Dictionaries that Share Same Key:Value

I know this can be done with lists, but I'm just trying to figure out how to do this with dictionaries.
Basically, it'll go like this:
dict1 = {'a': 10, 'b': 12, 'c': 9}
dict2 = {'a': 10, 'b': 3, 'c': 9}
def intersect(dict1, dict2):
combinDict = dict()
....
print(combinDict)
{'a': 10, 'c':9}
So I only want the keys with the same value added into a new dictionary.
Any help?
You want the intersection of the items:
dict1 = {'a': 10, 'b': 12, 'c': 9}
dict2 = {'a': 10, 'b': 3, 'c': 9}
print dict(dict1.viewitems() & dict2.items())
{'a': 10, 'c': 9}
For python 3 you just want to use items:
dict(dict1.items() & dict2.items())
dict1.items() & dict2.items() returns a set of key/value pairings that are common to both dicts:
In [4]: dict1.viewitems() & dict2.items()
Out[4]: {('a', 10), ('c', 9)}
Then we simply call the dict constructor on that.
Another way to do this would be to use a dict comprehension:
In [1]: dict1 = {'a': 10, 'b': 12, 'c': 9}
In [2]: dict2 = {'a': 10, 'b': 3, 'c': 9}
In [3]: {key: dict1[key] for key in dict1 if dict1[key] == dict2.get(key)}
Out[3]: {'a': 10, 'c': 9}
This should be teeny weeny bit faster, though that wouldn't matter for regular dictionaries.

Categories

Resources