在字典的字典列表上使用 reduce
Using reduce on a list of dictionaries of dictionaries
这是给定的列表。
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
我需要使用 map 和 reduce 函数,这样我才能得到
的最终结果
{'dogs': 10, 'cats': 7, 'fish': 4}
我用 map 写了一个函数
def addDict(d):
d2 = {}
for outKey, inKey in d.items():
for inVal in inKey:
if inVal in d2:
d2[inVal] += inKey[inVal]
else:
d2[inVal] = inKey[inVal]
return d2
def addDictN(L):
d2 = list(map(addDict, L))
print(d2)
那个returns
[{'dogs': 5, 'cats': 5, 'fish': 1}, {'dogs': 5, 'cats': 2, 'fish': 3}]
它结合了第一和第二字典的f1和f2,但我不确定如何在字典上使用reduce来得到最终结果。
您可以使用 collections.Counter
来总结您的反字典列表。
此外,您的字典扁平化逻辑可以通过 itertools.chain
进行优化。
from itertools import chain
from collections import Counter
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
lst = list(chain.from_iterable([i.values() for i in Pets]))
lst_sum = sum(map(Counter, lst), Counter())
# Counter({'cats': 7, 'dogs': 10, 'fish': 4})
这适用于任意长度的字典列表,没有跨字典的键匹配要求。
sum
的第二个参数是起始值。它被设置为一个空的 Counter 对象以避免 TypeError
.
如果不使用 map
和 reduce
,我会倾向于这样做:
from collections import defaultdict
result = defaultdict()
for fdict in pets:
for f in fdict.keys():
for pet, count in fdict[f].items():
result[pet] += count
使用 reduce
(这确实是 不是 适合工作的正确功能,并且不在 Python 3 中)您当前的进度将是像这样:
from collections import Counter
pets = [{'dogs': 5, 'cats': 5, 'fish': 1}, {'dogs': 5, 'cats': 2, 'fish': 3}]
result = reduce(lambda x, y: x + Counter(y), pets, Counter())
您可以像这样纯粹使用 map
和 reduce
:
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
new_pets = reduce(lambda x, y:[b.items() for _, b in x.items()]+[b.items() for _, b in y.items()], Pets)
final_pets = dict(reduce(lambda x, y:map(lambda c:(c, dict(x).get(c, 0)+dict(y).get(c, 0)), ['dogs', 'cats', 'fish']), new_pets))
输出:
{'fish': 4, 'cats': 7, 'dogs': 10}
这是给定的列表。
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
我需要使用 map 和 reduce 函数,这样我才能得到
的最终结果{'dogs': 10, 'cats': 7, 'fish': 4}
我用 map 写了一个函数
def addDict(d):
d2 = {}
for outKey, inKey in d.items():
for inVal in inKey:
if inVal in d2:
d2[inVal] += inKey[inVal]
else:
d2[inVal] = inKey[inVal]
return d2
def addDictN(L):
d2 = list(map(addDict, L))
print(d2)
那个returns
[{'dogs': 5, 'cats': 5, 'fish': 1}, {'dogs': 5, 'cats': 2, 'fish': 3}]
它结合了第一和第二字典的f1和f2,但我不确定如何在字典上使用reduce来得到最终结果。
您可以使用 collections.Counter
来总结您的反字典列表。
此外,您的字典扁平化逻辑可以通过 itertools.chain
进行优化。
from itertools import chain
from collections import Counter
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
lst = list(chain.from_iterable([i.values() for i in Pets]))
lst_sum = sum(map(Counter, lst), Counter())
# Counter({'cats': 7, 'dogs': 10, 'fish': 4})
这适用于任意长度的字典列表,没有跨字典的键匹配要求。
sum
的第二个参数是起始值。它被设置为一个空的 Counter 对象以避免 TypeError
.
如果不使用 map
和 reduce
,我会倾向于这样做:
from collections import defaultdict
result = defaultdict()
for fdict in pets:
for f in fdict.keys():
for pet, count in fdict[f].items():
result[pet] += count
使用 reduce
(这确实是 不是 适合工作的正确功能,并且不在 Python 3 中)您当前的进度将是像这样:
from collections import Counter
pets = [{'dogs': 5, 'cats': 5, 'fish': 1}, {'dogs': 5, 'cats': 2, 'fish': 3}]
result = reduce(lambda x, y: x + Counter(y), pets, Counter())
您可以像这样纯粹使用 map
和 reduce
:
Pets = [{'f1': {'dogs': 2, 'cats': 3, 'fish': 1},
'f2': {'dogs': 3, 'cats': 2}},
{'f1': {'dogs': 5, 'cats': 2, 'fish': 3}}]
new_pets = reduce(lambda x, y:[b.items() for _, b in x.items()]+[b.items() for _, b in y.items()], Pets)
final_pets = dict(reduce(lambda x, y:map(lambda c:(c, dict(x).get(c, 0)+dict(y).get(c, 0)), ['dogs', 'cats', 'fish']), new_pets))
输出:
{'fish': 4, 'cats': 7, 'dogs': 10}