I'd like to sum up all values in multiple Python dictionaries with the same key and keep the other values as is if they have a different key.
The input dictionaries would look something like this:
dict1 = {'A':{'a':1, 'b':2, 'c':0}, 'B':{'a':3, 'b':0, 'c':0}}
dict2 = {'A':{'a':3, 'c':1, 'd':5}, 'B':{'a':2, 'b':0, 'c':1}, 'C':{'a':1, 'b':2, 'c':1}}
Output:
dict3 = {'A':{'a':4, 'b':2, 'c':1, 'd':5}, 'B':{'a':5, 'b':0, 'c':1}, 'C':{'a':1, 'b':2, 'c':1}}
Is there any way to achieve this result using only the standard library? This should also work with more than 2 dictionaries.
Very structure dependent, however something like ...
dicts = [
{'A':{'a':1, 'b':2, 'c':0}, 'B':{'a':3, 'b':0, 'c':0}},
{'A':{'a':3, 'c':1, 'd':5}, 'B':{'a':2, 'b':0, 'c':1}, 'C':{'a':1, 'b':2, 'c':1}}
]
odict = {}
for d in dicts:
for dk in d.keys():
if dk not in odict:
odict[dk] = {}
for inner_dk in d[dk].keys():
if inner_dk not in odict[dk]:
odict[dk][inner_dk] = d[dk][inner_dk]
else:
odict[dk][inner_dk] += d[dk][inner_dk]
print(odict)
A function that accepts multiple dicts:
dict1 = {"A": {"a": 1, "b": 2, "c": 0}, "B": {"a": 3, "b": 0, "c": 0}}
dict2 = {
"A": {"a": 3, "c": 1, "d": 5},
"B": {"a": 2, "b": 0, "c": 1},
"C": {"a": 1, "b": 2, "c": 1},
}
def merge_dicts(*dicts):
if not dicts:
return
out = {}
all_keys = set(dicts[0]).union(k for d in dicts[1:] for k in d)
for k in all_keys:
out[k] = {}
for kk in set(dicts[0].get(k, {})).union(
k_ for d in dicts[1:] for k_ in d.get(k, {})
):
out[k][kk] = sum(d.get(k, {}).get(kk, 0) for d in dicts)
return out
print(merge_dicts(dict1, dict2))
Prints:
{'C': {'c': 1, 'a': 1, 'b': 2}, 'A': {'c': 1, 'd': 5, 'a': 4, 'b': 2}, 'B': {'c': 1, 'a': 5, 'b': 0}}
For input:
dict1 = {"A": {"a": 1, "b": 2, "c": 0}, "B": {"a": 3, "b": 0, "c": 0}}
dict2 = {
"A": {"a": 3, "c": 1, "d": 5},
"B": {"a": 2, "b": 0, "c": 1},
"C": {"a": 1, "b": 2, "c": 1},
}
dict3 = {
"A": {"a": 100},
}
print(merge_dicts(dict1, dict2, dict3))
Prints:
{'A': {'a': 104, 'b': 2, 'c': 1, 'd': 5}, 'B': {'a': 5, 'b': 0, 'c': 1}, 'C': {'a': 1, 'b': 2, 'c': 1}}
Related
I have two lists that I need to merge based on a column name that exists in both. The source is JSON.
I'm not sure how to do this, I looked at How to merge multiple dicts with same key? but that one doesn't constrain anything.
Example:
dict1 = {"a": 3, 'b': 4}
dict2 = {"a": 3, 'c': 5}
dict3 = {"a": 1, 'b': 2}
dict4 = {"a": 1, 'c': 8}
dict_result = [{"a": 3, 'b': 4, 'c': 5},{"a": 1, 'b': 2, 'c': 8}]
BR
Here try this.
dict1 = {"a": 3, 'b': 4}
dict2 = {"a": 3, 'c': 5}
dict3 = {"a": 1, 'b': 2}
dict4 = {"a": 1, 'c': 8}
def merge_dictionary(*args):
dictionary = []
dict_result=[]
app_index = 0 # append index
for dic in (args):
for item, value in dic.items():
if [item, value] not in dictionary:
dictionary.append([item, value])
for index, x in enumerate(dictionary):
if index%3==0:
dict_result.append({x[0]:x[1]})
app_index = index
else:
dict_result[app_index//3].update({x[0]:x[1]})
return dict_result
print(merge_dictionary(dict1, dict2, dict3, dict4))
I'm new to python and trying to find a solution to the problem:
The problem is to write a function that scans the array of records and returns the record that has the minimum value for a specified key. Records that do not contain the specified key are considered to have value 0 for the key.
Note that keys may map to negative values!
My solution:
def min_by_key(k,ld):
min_val=min([d.get(k,0) for d in ld])
for dt in ld:
if dt.get(k,0)==min_val:
return dt
assert min_by_key("a", [{"a": 1, "b": 2}, {"a": 2}]) == {"a": 1, "b": 2}
assert min_by_key("a", [{"a": 2}, {"a": 1, "b": 2}]) == {"a": 1, "b": 2}
assert min_by_key("b", [{"a": 1, "b": 2}, {"a": 2}]) == {"a": 2}
assert min_by_key("a", [{}]) == {}
assert min_by_key("b", [{"a": -1}, {"b": -1}]) == {"b": -1}
It is working but need to know is there any better way to do this.
Just use min with key that compares key value k
>>> def min_by_key(k,ld):
... return min(ld, key=lambda d: d.get(k, 0))
...
>>>
All your asserts pass
>>> assert min_by_key("a", [{"a": 1, "b": 2}, {"a": 2}]) == {"a": 1, "b": 2}
>>> assert min_by_key("a", [{"a": 2}, {"a": 1, "b": 2}]) == {"a": 1, "b": 2}
>>> assert min_by_key("b", [{"a": 1, "b": 2}, {"a": 2}]) == {"a": 2}
>>> assert min_by_key("a", [{}]) == {}
>>> assert min_by_key("b", [{"a": -1}, {"b": -1}]) == {"b": -1}
>>>
This is as simple as this:
def min_by_key(key, dicts):
return min(dicts, key=lambda d: d.get(key, 0))
In this way you can sort by key, and in case there is no such value in a dict 0 is used.
I am stuck on convert jsons from regular (key-value) to nested.
for example:
j = { 'a': 5,
'b': 3,
'c.c1': 2,
'c.c2':5,
'd.dd.d1': 0,
'd.dd.d2':9
}
and I need to get:
new_j = {
'a': 5,
'b': 3,
'c':
{'c1': 2,
'c2':5}
'd':
{'dd' :
{'d1': 0,
'd2': 9}
},
}
there are easy method to do this?
How about this?
j_new = {}
for key,value in j.items():
keys = key.split('.')
level = j_new
for key in keys[:-1]:
if key not in level:
level[key]={}
level = level[key]
level[keys[-1]]=value
print(j_new)
Which returns:
{'a': 5, 'b': 3, 'c': {'c1': 2, 'c2': 5}, 'd': {'dd': {'d1': 0, 'd2': 9}}}
Try this:
d = {}
def setValue(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
for k,v in j.items():
setValue(d, k.split('.'), v)
Output:
{
"a": 5,
"c": {
"c2": 5,
"c1": 2
},
"b": 3,
"d": {
"dd": {
"d2": 9,
"d1": 0
}
}
}
how to recursively sort all nested iterable in an iterable?
e.g.
d = {
'e': [{'y': 'y'}, {'x': [{'2': 2, '1': 1}]}],
'x': ['c', 'b', 'a'],
'z': {
'a': [3, 1, 2],
'd': [{'y': [6,5,1]}, {'w': 1}],
'c': {'2': 2, '3': 3, '4': 4}
},
'w': {1:1, 2:2, 3:3}
}
I was the output like
{'e': [{'x': [{'1': 1, '2': 2}]}, {'y': 'y'}],
'w': {1: 1, 2: 2, 3: 3},
'x': ['a', 'b', 'c'],
'z': {'a': [1, 2, 3],
'c': {'2': 2, '3': 3, '4': 4},
'd': [{'w': 1}, {'y': [1, 5, 6]}]}}
from pprint import pprint
d = {
'e': [{'y': 'y'}, {'x': [{'2': 2, '1': 1}]}],
'x': ['c', 'b', 'a'],
'z': {
'a': [3, 1, 2],
'd': [{'y': [6,5,1]}, {'w': 1}],
'c': {'2': 2, '3': 3, '4': 4}
},
'w': {1:1, 2:2, 3:3}
}
def rec_sort(iterable):
"""Recursively sort
"""
def sort_dict_key(x):
if isinstance(x, dict):
return sorted(x.keys(), key=sort_dict_key)
return x
if isinstance(iterable, dict):
d = {}
for k, v in iterable.items():
d[k] = rec_sort(v)
elif isinstance(iterable, list):
iterable.sort(key=sort_dict_key)
for pos,item in enumerate(iterable):
iterable[pos] = rec_sort(item)
return iterable
pprint(rec_sort(d))
You can use recursion:
import json
d = {'x': ['c', 'b', 'a'], 'z': {'a': [3, 1, 2], 'c': {'3': 3, '2': 2, '4': 4}, 'd': [{'y': [6, 5, 1]}, {'w': 1}]}, 'e': [{'y': 'y'}, {'x': [{'1': 1, '2': 2}]}], 'w': {1: 1, 2: 2, 3: 3}}
def sort_nested(c):
if not isinstance(c, dict):
return sorted(c) if isinstance(c, list) else c
return {a:sorted(sort_nested(i) for i in b) if isinstance(b, list) else sort_nested(b) for a, b in c.items()}
print(json.dumps(sort_nested(d), indent=4))
Output:
{
"x": [
"a",
"b",
"c"
],
"z": {
"a": [
1,
2,
3
],
"c": {
"3": 3,
"2": 2,
"4": 4
},
"d": [
{
"w": 1
},
{
"y": [
1,
5,
6
]
}
]
},
"e": [
{
"x": [
{
"1": 1,
"2": 2
}
]
},
{
"y": "y"
}
],
"w": {
"1": 1,
"2": 2,
"3": 3
}
}
I have the below json, I want to add one more property:
[ {
"A": 1,
"B": "str"
},
{
"A": 2,
"B": "str2"
},
{
"A": 3,
"B": "str3"
}
]
So I want something like this:
[ {
"A": 1,
"B": "str",
"C": "X"
},
{
"A": 2,
"B": "str2",
"C": "X"
},
{
"A": 3,
"B": "str3",
"C": "X"
}
]
What is the best way to do this?
Loop through each dict obj in the list and add required key value pair that you want:
List Before
list1 = [
{
"A": 1,
"B": "str"
},
{
"A": 2,
"B": "str2"
},
{
"A": 3,
"B": "str3"
}
]
The code
for l in list1:
l['C'] = 'X'
print(list1)
List After i.e Output
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]
>>> j = [ { "A": 1, "B": "str" }, { "A": 2, "B": "str2" }, { "A": 3, "B": "str3" } ]
>>> [i.update({'C': 'X'}) for i in j]
>>> j
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]
Or, as per coldspeed's comment:
>>> for item in j:
... item['C'] = 'X'
...
>>> j
[{'A': 1, 'B': 'str', 'C': 'X'}, {'A': 2, 'B': 'str2', 'C': 'X'}, {'A': 3, 'B': 'str3', 'C': 'X'}]