I am pretty sure that I must be missing something really basic but, is there a way to map a dictionary with another one?.
For instance given a dictionary like this:
d = {'a': {'b': 'r1', 'c': 'r2'}, 'v': {'x': 'r4', 'o': 'r2'}}
And use a mapper like this:
mapper = {'a': 0, 'b': 1, 'c': 2, 'v': 3, 'x': 4, 'o': 5}
The expected output should be like this:
result = {0: {1: 'r1', 2: 'r2'}, 3: {4: 'r4', 5: 'r2'}}
You can use a function that recursively replaces keys with corresponding values in the mapper dict:
def map_keys(d, m):
return {m[k]: map_keys(v, m) for k, v in d.items()} if isinstance(d, dict) else d
so that map_keys(d, mapper) returns:
{0: {1: 'r1', 2: 'r2'}, 3: {4: 'r4', 5: 'r2'}}
This is not recursive, hence only works for similar input (if you're fine):
d = {'a': {'b': 'r1', 'c': 'r2'}, 'v': {'x': 'r4', 'o': 'r2'}}
mapper = {'a': 0, 'b': 1, 'c': 2, 'v': 3, 'x': 4, 'o': 5}
res = {}
for k, v in d.items():
res.update({mapper[k]: {mapper[x]: y for x, y in v.items()}})
print(res)
# {0: {1: 'r1', 2: 'r2'}, 3: {4: 'r4', 5: 'r2'}}
Shorter:
res = {mapper[k]: {mapper[x]: y for x, y in v.items()} for k, v in d.items()}
Related
I have 2 array of objects:
a = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
b = [{'a': 1, 'b': 2}, {'g': 3, 'h': 4}, {'f': 6, 'e': 5}]
Output:
a - b = [{'c': 3, 'd': 4}] ("-" symbol is only for representation, showing difference. Not mathematical minus.)
b - a = [{'g': 3, 'h': 4}]
In every array, the order of key may be different. I can try following and check for that:
for i in range(len(a)):
current_val = a[i]
for x, y in current_val.items:
//search x keyword in array b and compare it with b
but this approach doesn't feel right. Is there simpler way to do this or any utility library which can do this similar to fnc or pydash?
You can use lambda:
g = lambda a,b : [x for x in a if x not in b]
g(a,b) # a-b
[{'c': 3, 'd': 4}]
g(b,a) # b-a
[{'g': 3, 'h': 4}]
Just test if all elements are in the other array
a = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
b = [{'a': 1, 'b': 2}, {'g': 3, 'h': 4}, {'f': 6, 'e': 5}]
def find_diff(array_a, array_b):
diff = []
for e in array_a:
if e not in array_b:
diff.append(e)
return diff
print(find_diff(a, b))
print(find_diff(b, a))
the same with list comprehension
def find_diff(array_a, array_b):
return [e for e in array_a if e not in array_b]
here is the code for subtracting list of dictionaries
a = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 6, 'f': 6}]
b = [{'a': 1, 'b': 2}, {'g': 3, 'h': 4}, {'f': 6, 'e': 6}]
a_b = []
b_a = []
for element in a:
if element not in b:
a_b.append( element )
for element in b:
if element not in a:
b_a.append( element )
print("a-b =",a_b)
print("b-a =",b_a)
I am a beginner in python trying to create a function that filters through my nested dictionary through by asking multiple values in a dictionary like
filtered_options = {'a': 5, 'b': "Cloth'}
For my dictionary
my_dict = {1.0:{'a': 1, 'b': "Food', 'c': 500, 'd': 'Yams'},
2.0:{'a': 5, 'v': "Cloth', 'c': 210, 'd': 'Linen'}}
If I input my dictionary in the filter function with such options I should get something that looks like
filtered_dict(my_dict, filtered_options = {'a': 5, 'b': "Cloth'})
which outputs the 2nd key and other keys with the same filtered options in my dictionary.
This should do what you want.
def dict_matches(d, filters):
return all(k in d and d[k] == v for k, v in filters.items())
def filter_dict(d, filters=None):
filters = filters or {}
return {k: v for k, v in d.items() if dict_matches(v, filters)}
Here's what happens when you test it:
>>> filters = {'a': 5, 'b': 'Cloth'}
>>> my_dict = {
... 1.0: {'a': 1, 'b': 'Food', 'c': 500, 'd': 'Yams'},
... 2.0: {'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}
... }
>>> filter_dict(my_dict, filters)
{2.0: {'b': 'Cloth', 'a': 5, 'd': 'Linen', 'c': 210}}
You can do this :
import operator
from functools import reduce
def multi_level_indexing(nested_dict, key_list):
"""Multi level index a nested dictionary, nested_dict through a list of keys in dictionaries, key_list
"""
return reduce(operator.getitem, key_list, nested_dict)
def filtered_dict(my_dict, filtered_options):
return {k : v for k, v in my_dict.items() if all(multi_level_indexing(my_dict, [k,f_k]) == f_v for f_k, f_v in filtered_options.items())}
So that:
my_dict = {1.0:{'a': 1, 'b': 'Food', 'c': 500, 'd': 'Yams'},
2.0:{'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}}
will give you:
print(filtered_dict(my_dict, {'a': 5, 'b': 'Cloth'}))
# prints {2.0: {'a': 5, 'b': 'Cloth', 'c': 210, 'd': 'Linen'}}
I have output from python networkX code:
flow_value, flow_dict = nx.maximum_flow(T, 'O', 'T')
print(flow_dict)
#Output as followesenter
#{'O': {'A': 4, 'B': 6, 'C': 4}, 'A': {'B': 1, 'D': 3}, 'B': {'C': 0, 'E': 3,'D': 4}, 'C': {'E': 4}, 'E': {'D': 1, 'T': 6}, 'D': {'T': 8}, 'T': {}}
I want to extract all the data in the form looks like:
#('O','A',4),('O','B','6'),('O','C','4'),('A','B',1),......,('D','T',8)
Any ways can I traverse thru the nested dict and get the data I need?
I tried this and it works. Some type checking to only capture strings
def retrieve_all_strings_from_dict(nested_dict, keys_to_ignore = None):
values = []
if not keys_to_ignore:
keys_to_ignore = []
else: keys_to_ignore = to_list(keys_to_ignore)
if not isinstance(nested_dict,dict):
return values
dict_stack = []
dict_stack.append(nested_dict)
for dict_var in dict_stack:
data_list = [v for k,v in dict_var.items() if all([isinstance(v,str), k not in keys_to_ignore]) ]
additional_dicts = [v for k,v in dict_var.items() if isinstance(v,dict)]
for x in additional_dicts:
dict_stack.append(x)
for w in data_list:
values.append(w)
return values
I have 2 dicts like:
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
The merging result I want should be:
z = {3: {'a':1}, 2: {'a':3, 'b':1, 'c':2}}
I tried dict(x.items() + y.items()) and Counter, but only get
{2: {'a': 2, 'c': 2}, 3: {'a': 1}}
as a result.
How can I merge dict whose value is also a dict itself?
I have explained that the difference between How to merge two Python dictionaries in a single expression?
is that my dict's value is also a dict.
What about this:
For Python2.x:
from collections import Counter
y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
t=x.copy()
print(dict({k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t))
Result:
{1: {'a': 1, 'b': 1}, 2: {'a': 3, 'c': 2, 'b': 1}, 3: {'a': 1}}
For Python3.5+:
{**{k: (dict(Counter(t.pop(k, None)) + Counter(v))) for k, v in y.items()},**t}
Here you have a possible solution. Although it doesn't use any library, it is quite complex.
Also it will work with any two dictionaries, independently on which is the largest.
{key: {ikey: x.get(key, {}).get(ikey, 0) + y.get(key, {}).get(ikey, 0)
for ikey in x.get(key, {}).keys()+y.get(key, {}).keys()}
for key in x.keys()+y.keys()}
Output:
{2: {'a': 3, 'b': 1, 'c': 2}, 3: {'a': 1}}
Suppose for any same depth for a certain key, in two dicts the values are of same type (both dict or both number, i don't know how to define merging a number into a dict).
def merge(d1, d2):
for i in d2:
if i not in d1:
continue
if isinstance(d1[i], dict) and isinstance(d2[i], dict):
merge(d1[i], d2[i])
else:
d2[i] += d1[i]
d1.pop(i)
for j in d1:
d2[j] = d1[j]
It's straightforward but maybe not elegant.
Use collections.Counter to "merge" the items you want to merge (only the common keys), and leave the others intact, using a double ternary expression in a dict comprehension, iterating on the union of the keys:
import collections
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
# pre-compute common keys, one-liners are not the ultimate goal in life!
common_keys = set(x) & set(y)
# now generate the merged dict
result = {k:collections.Counter(x[k])+collections.Counter(y[k]) if k in common_keys else x[k] if k in x else y[k] for k in set(x)|set(y)}
print(result)
result:
{2: Counter({'a': 3, 'c': 2, 'b': 1}), 3: {'a': 1}}
Note: we could have avoided computing the common keys beforehand by replacing:
if k in common_keys
by
if k in x and k in y
This works:
x = {2: {'a':1, 'b':1}}
y = {3: {'a':1}, 2: {'a':2, 'c':2}}
def key_merge (dict1, dict2):
## function which checks for any matching keys, and merges them
if len(dict1.keys()) == 0 or len(dict2.keys()) == 0:
return {}
else:
for key in dict1.keys():
if key in dict2.keys():
return {key:{ k: dict1[key].get(k, 0) + dict2[key].get(k, 0) for k in set(dict1[key])|set(dict2[key]) }}
z = {**x, **y, **key_merge(x, y)}
Again, up to you if it's elegant!
I don't know what your definition of 'elegantly' is but assuming you mean readable then perhaps this way will suit you.
from collections import Counter
def counter_dict(in_dict):
"""
Create a dict of Counters from a dict of dicts.
"""
return dict((k, Counter(v)) for (k, v) in in_dict.items())
def merge_counter_dicts(a, b):
"""
Create a dict of Counters from two dicts of Counters.
Where keys exist in both counts are summed.
"""
out_dict = a.copy()
for k in b.keys():
out_dict[k] = out_dict.setdefault(k, Counter()) + b[k]
return out_dict
x = {2: {'a': 1, 'b': 1}}
y = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
xc = counter_dict(x)
xy = counter_dict(y)
print merge_counter_dicts(xc, xy)
# What about something like this:
# merge_nested_dicts.py
# tested under Python3.6
# assuming dict_02 overwrites dict_01
# one liner functional style
def deep_merge(dict_01, dict_02):
return {k: {**dict_01.get(k), **dict_02.get(k)} if k in dict_01 and
isinstance(dict_01.get(k), dict) and
isinstance(dict_02.get(k), dict) else v
for k, v in {**dict_01, **dict_02}.items()}
if __name__ == '__main__':
y = {2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
x = {3: {'a': 1}, 2: {'a': 2, 'c': 2}}
print(x)
print(y)
print(deep_merge(x, y))
'''
{3: {'a': 1}, 2: {'a': 2, 'c': 2}}
{2: {'a': 1, 'b': 1}, 1: {'a': 1, 'b': 1}}
{3: {'a': 1}, 2: {'a': 1, 'c': 2, 'b': 1}, 1: {'a': 1, 'b': 1}}
'''
I'd like to add the values of a dictionary to another dictionary. For example:
adict = {1: {'a': 13, 'b': 19, 'c': 15}, 2: {'a': 7, 'b': 2, 'c': 0}}
If we add {1: {'a': 3, 'b': 9, 'c': 23}} to adict
Then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 7, 'b': 2, 'c': 0}}
If we add {3: {'a': 4}} then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 7, 'b': 2, 'c': 0}, 3: {'a': 4}}
and if we add {2: {'a': 1, 'b': 8, 'c': 27, 'd': 11}}
Then adict should now be:
{1: {'a': 16, 'b': 28, 'c': 38}, 2: {'a': 8, 'b': 10, 'c': 27, 'd': 11}, 3: {'a': 4}}
What's the best way to do this?
Simple recursive function:
>>> adict = {1: {'a': 13, 'b': 19, 'c':15}, 2: {'a': 7, 'b': 2, 'c':0}}
>>> def dict_add(a,b):
... a = a.copy()
... for k,v in b.items():
... if isinstance(v,(dict,)):
... a[k] = dict_add(a.get(k,{}),v)
... else:
... a[k] = a.get(k,0) + v
... return a
...
>>> dict_add(adict,{1: {'a': 3, 'b': 9, 'c': 23}})
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}}
>>> dict_add(dict_add(adict,{1: {'a': 3, 'b': 9, 'c': 23}}),{3:{'a':4}})
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}, 3: {'a': 4}}
This is probably very inefficient, but here's what I came up with:
def dict_add(a, b):
result = dict(a)
for key, value in b.items():
if type(value) != dict:
result[key] = result.get(key, 0) + value
else:
result[key] = dict_add(result.get(key, {}), value)
return result
Running this code results in this:
>>> adict = {1: {'a': 13, 'b': 19, 'c':15}, 2: {'a': 7, 'b': 2, 'c':0}}
>>> bdict = {1: {'a': 3, 'b': 9, 'c': 23}}
>>>
>>> print dict_add(adict, bdict)
{1: {'a': 16, 'c': 38, 'b': 28}, 2: {'a': 7, 'c': 0, 'b': 2}}
Here is a functional solution. The rec_add function does what you ask with arbitrarily nested dictionaries.
def combine(f, d1, d2):
"""Create a new dict combining d1 and d2.
Keys appearing only in one of the input dict are copied unmodified. Values
with matching keys are combined using f and copied in the output dict."""
keys = set(d1.keys() + d2.keys())
out = { }
for key in keys:
if key in d1:
if key in d2:
out[key] = f(d1[key], d2[key])
else:
out[key] = d1[key]
else:
out[key] = d2[key]
return out
def rec_combine(f, d1, d2):
"""Recursively combine all dicts."""
def aux(v1, v2):
if isinstance(v1, (dict,)) and isinstance(v2, (dict,)):
return rec_combine(f, v1, v2)
else:
return f(v1, v2)
return combine(aux, d1, d2)
def rec_add(d1, d2):
"""Recursively sum values in d1 and d2."""
return rec_combine(lambda x, y: x + y, d1, d2)