I have a list of dicts, like this:
x = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
and I would like to have a something like this
x = [{'a': 4}, {'b': 2}, {None: 0}]
What is the most memory-friendly way to reach that?
You can also use collections.Counter, which will naturally update the counts:
from collections import Counter
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = Counter()
for d in l:
counts.update(d)
print([{k: v} for k, v in counts.items()])
From the docs for collections.Counter.update:
Elements are counted from an iterable or added-in from another mapping (or counter). Like dict.update() but adds counts instead of replacing them. Also, the iterable is expected to be a sequence of elements, not a sequence of (key, value) pairs.
You can also use a collections.defaultdict to do the counting:
from collections import defaultdict
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = defaultdict(int)
for d in l:
for k, v in d.items():
counts[k] += v
print([{k: v} for k, v in counts.items()])
Or you could also count with initializing 0 yourself:
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = {}
for d in l:
for k, v in d.items():
counts[k] = counts.get(k, 0) + 1
print([{k: v} for k, v in counts.items()])
From the docs for dict.get:
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
Output:
[{'a': 4}, {'b': 2}, {None: 0}]
Lets say:
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
Now we will extract and add up:
res = []
for k in l:
for i in k:
s = {i:sum(j[i] for j in l if i in j)}
if s not in res:
res.append(s)
gives:
[{'a': 4}, {'b': 2}, {None: 0}]
Or we could use (adapted from here ):
result = {}
for d in l:
for k in d.keys():
result[k] = result.get(k, 0) + d[k]
res = [{i:result[i]} for i in result]
Check the one-line code using pandas.
L = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
output = pd.DataFrame(L).sum(axis = 0).to_dict()
Related
I've got a nested dictionary:
{'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
is there a simple way of removing all the nested zero values so the dictionary becomes:
{'a': {'m': 1}, 'b': {'x': 1}}
Dictionary comprehension:
>>> d = {'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
>>> {key: {k:v for k,v in d[key].items() if v != 0} for key in d}
Output:
{'a': {'m': 1}, 'b': {'x': 1}}
One approach, that modifies the dictionary in-place:
d = {'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
for dd in d.values():
for k, v in list(dd.items()):
if v == 0:
dd.pop(k)
print(d)
Output
{'a': {'m': 1}, 'b': {'x': 1}}
You can use dict comprehension:
d = {'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
result = {k: {k1: v1 for k1, v1 in v.items() if v1 != 0} for k, v in d.items()}
One-line solution:
d = {'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
d_new = {k: {inner_k: inner_v for inner_k, inner_v in v.items() if inner_v != 0} for k, v in d.items()}
print(d_new) # Prints: {'a': {'m': 1}, 'b': {'x': 1}}
dict_1 = {'a': {'m': 1, 'n': 0}, 'b': {'m': 0, 'x': 1}}
new_dict_1={}
for key in dict_1.keys():
for v,k in zip(dict_1[key].values(),dict_1[key].keys()):
if v != 0 :
new_dict_1[key] = {k:v}
new_dict_1
You can even try to convert your nested dict to flat and then look for value zero
Code:
[d[k[0]].pop(k[-1]) for k,v in pd.json_normalize(d).to_dict(orient='records')[0].items() if v==0]
d
Do I have any opportunity to rewrite the code below with dict enhancement? (if I name it right, mean {k: v for k, v in ...})
list_of_dicts = [{'a': 1}, {'b': 2}, {'b': 20, 'c': 3}, {'a': 10, 'b': 2}]
for k, v in [p for d in list_of_dicts for p in d.items()]:
d[k] = d.setdefault(k, set()) | {v}
sure why not :). but it is nested at bit 😉
import itertools
list_of_dicts = [{'a': 1}, {'b': 2}, {'b': 20, 'c': 3}, {'a': 10, 'b': 2}]
o = {k: {d[k] for d in list_of_dicts if k in d} for k in itertools.chain.from_iterable(list_of_dicts)}
print(o)
This question already has answers here:
Appending a dictionary to a list in a loop
(5 answers)
Closed 1 year ago.
I want an output like this:
[{'a': 0}, {'a': 1}, {'a': 2}, {'a': 3}]
But I am getting this output:
[{'a': 3}, {'a': 3}, {'a': 3}, {'a': 3}]
I tried the below code:
l = []
d = {}
for i in range(0,4):
d['a'] = i
print("dictinary ",d)
print("list before appending ",l)
l.append(d)
print("list after appending ",l)
print(l)
I am getting the below output after applying print statements(for debugging)
dictinary {'a': 0}
list before appending []
list after appending [{'a': 0}]
dictinary {'a': 1}
list before appending [{'a': 1}]
list after appending [{'a': 1}, {'a': 1}]
dictinary {'a': 2}
list before appending [{'a': 2}, {'a': 2}]
list after appending [{'a': 2}, {'a': 2}, {'a': 2}]
dictinary {'a': 3}
list before appending [{'a': 3}, {'a': 3}, {'a': 3}]
list after appending [{'a': 3}, {'a': 3}, {'a': 3}, {'a': 3}]
[{'a': 3}, {'a': 3}, {'a': 3}, {'a': 3}]
I cannot understand one thing: Why my list value is getting changed on changing dictionary value ? i.e. On executing line no 4 in code, the value of the list is automatically getting changed(See line no 5 of output). Please suggest something.
create new dictionary In for-loop. in Your code you have one dictionary with one address when changing one of them all changing.
Try this:
l = []
for i in range(0,4):
d = {}
d['a'] = i
print("dictinary ",d)
print("list before appending ",l)
l.append(d)
print("list after appending ",l)
print(l)
Output:
dictinary {'a': 0}
list before appending []
list after appending [{'a': 0}]
dictinary {'a': 1}
list before appending [{'a': 0}]
list after appending [{'a': 0}, {'a': 1}]
dictinary {'a': 2}
list before appending [{'a': 0}, {'a': 1}]
list after appending [{'a': 0}, {'a': 1}, {'a': 2}]
dictinary {'a': 3}
list before appending [{'a': 0}, {'a': 1}, {'a': 2}]
list after appending [{'a': 0}, {'a': 1}, {'a': 2}, {'a': 3}]
[{'a': 0}, {'a': 1}, {'a': 2}, {'a': 3}]
Here is my code.
>>> a = [{'a': 1}, {'b': 2}]
>>> b = [{'c': 3}, {'d': 4}]
I want to show:
[{'a':1, 'c':3}, {'b':2, 'c':3}, {'a':1, 'd':4}, {'b':2, 'd':4}]
Is there a way I can do it only with list/dict comprehension?
A one line, no import solution can consist of a lambda function:
f = lambda d, c:[c] if not d else [i for k in d[0] for i in f(d[1:], {**c, **k})]
a = [{'a': 1}, {'b': 2}]
b = [{'c': 3}, {'d': 4}]
print(f([a, b], {}))
Output:
[{'a': 1, 'c': 3}, {'a': 1, 'd': 4}, {'b': 2, 'c': 3}, {'b': 2, 'd': 4}]
However, a much cleaner solution can include itertools.product:
from itertools import product
result = [{**j, **k} for j, k in product(a, b)]
Output:
[{'a': 1, 'c': 3}, {'a': 1, 'd': 4}, {'b': 2, 'c': 3}, {'b': 2, 'd': 4}]
You can try this.
a = [{'a': 1}, {'b': 2}]
b = [{'c': 3}, {'d': 4}]
d = [ {**i, **j} for i in a for j in b ]
print(d)
I have a list of dicts, and I'd like to remove the dicts with identical key and subtract the value pairs.
For this list:
[{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
I'd like to return this:
[{'chair': 1}, {'tv': 3}, {'laptop': 2}]
You could do it like this, creating an intermediate dict for efficiency:
dicts_list = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
out = {}
for d in dicts_list:
for key, val in d.items():
if key in out:
out[key] -= val
else:
out[key] = val
out_list = [ {key:val} for key, val in out.items()]
print(out_list)
# [{'tv': 3}, {'chair': 1}, {'laptop': 2}]
But you might be interested in this intermediate dict as output:
print(out)
# {'tv': 3, 'chair': 1, 'laptop': 2}
defaultdict from collections might come in handy. This solution will cover the cases where there are more than 2 dicts of the same key in the list.
from collections import defaultdict
ls = defaultdict(list)
d = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
# Creating a list of all values under one key
for dic in d:
for k in dic:
ls[k].append(dic[k])
print(ls)
defaultdict(<class 'list'>, {'chair': [4, 3], 'tv': [5, 2], 'laptop': [2]})
# safe proofing for negative values on subtraction
for k in ls:
ls[k].sort(reverse=True)
ls[k] = ls[k][0] - sum(ls[k][1:])
print(ls)
defaultdict(<class 'list'>, {'chair': 1, 'tv': 3, 'laptop': 2})
You can construct a defaultdict of lists, then use a list comprehension:
from collections import defaultdict
dd = defaultdict(list)
for d in data:
k, v = next(iter(d.items()))
dd[k].append(v)
res = [{k: v if len(v) == 1 else v[0] - sum(v[1:])} for k, v in dd.items()]
print(res)
# [{'chair': 1}, {'tv': 3}, {'laptop': [2]}]
Following snippet is using nothing but standard modules:
a= [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
print("Input:", a)
b=dict()
for element in a:
for k,v in element.items():
try:
# you didn't specify the subtracted element order,
# so I'm subtracting BIGGER from SMALLER using simple abs() :)
b[k] = abs(b[k] - v)
except:
b[k] = v
print("Output:", b)
# restore original structure
c = [ dict({item}) for item in b.items() ]
print("Output:", c)
And demo:
('Input:', [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}])
('Output:', {'tv': 3, 'chair': 1, 'laptop': 2})
('Output:', [{'tv': 3}, {'chair': 1}, {'laptop': 2}])
EDIT: Added the secondary out put C to restructure B similar to A