基于键的Python字典值求和

3
如何对字典中值为字符串的数值进行求和。也就是说,如何在字典中对相同键的多个值进行求和。

字典

values = [
    {
        "rashod": 0,
        "prihod": 230.0,
        "prod_name": "r",
        "prod_hola": "t"
    },
    {
        "rashod": 0,
        "prihod": 230.0,
        "prod_name": "r",
        "prod_hola": "t"
    },
    {
        "rashod": 0.0,
        "prihod": 0,
        "prod_name": "c",
        "prod_hola": "f"
    },
    {
        "rashod": 0,
        "prihod": 100.0,
        "prod_name": "c",
        "prod_hola": "f"
    },
    {
        "rashod": 0.0,
        "prihod": 0,
        "prod_name": "a",
        "prod_hola": "b"
    },
    {
        "rashod": 0,
        "prihod": 1500.0,
        "prod_name": "a",
        "prod_hola": "b"
    }]

python

dictf = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), values)
print dictf

但是这会将字典中的所有值相加,输出结果如下:
{'rashod': 1930.0, 'prihod': -17020.0, 'prod_name': 'abcfrtabcfrtabcfrt'}

我希望您能输出如下内容:

我想要的输出结果是这样的:

[{'rashod': 1930.0, 'prihod': -17020.0, 'prod_name': 'a','prod_hola':'b},
{'rashod': 1930.0, 'prihod': -17020.0, 'prod_name': 'c','prod_hola':'f},
{'rashod': 1930.0, 'prihod': -17020.0, 'prod_name': 'r','prod_hola':'t},]

3
提供与输入相匹配的输出。 - Karoly Horvath
你的输入/输出示例不明确:值应该仅在“prod_name”上重新分组,仅在“prod_hola”上重新分组还是在“prod_name”和“prod_hola”的组合上重新分组? - bruno desthuilliers
它们是“prod_name”和“prod_hola”的组合。 - Marin
1
哦,对了:Karoly Horvarth提到,你的示例输出与输入不匹配-你能提供匹配的输入和输出样本吗? - bruno desthuilliers
3个回答

4

具体解决方案,没有尝试巧妙的方法:

def regroup(values):
    groups = dict()
    for d in values:
        key = (d["prod_name"], d["prod_hola"])
        if key in groups:
            group = groups[key]
            group["rashod"] += d["rashod"]
            group["prihod"] += d["prihod"]
        else:
            groups[key] = d.copy()
    return list(groups.values())

还有一种通用的解决方案:

def generic_regroup(values, keys):
    groups = dict()
    valkeys = [k for k in values[0] if k not in key]
    for d in values:
        key = tuple(d[k] for k in keys)
        if key in groups:
            group = groups[key]
            for k in valkeys:
                group[k] += d[k]
        else:
            groups[key] = d.copy()
    return list(groups.values())

results = generic_regroup(values, ("prod_name", "prod_hola"))

现在肯定会有人提供一种更聪明的解决方案,其中涉及itertools...

有什么建议吗: https://stackoverflow.com/questions/66974191/get-sum-of-elemets-in-json-store-data-kivy-to-resolve-scroll-height-question - Nikola Lukic

1
这是一个简单而具体的解决方案,我相信还有更普遍和更巧妙的选择。 :)
from collections import defaultdict

pr = defaultdict(float)
ra = defaultdict(float)
for el in values:
    combi = (el['prod_name'], el['prod_hola'])
    pr[combi] += el['prihod']
    ra[combi] += el['rashod']

results = [dict(rashod=r, prihod=p, \
                prod_name=nh[0], prod_hola=nh[1]) \
           for r,p,nh in zip(ra.values(), pr.values(), pr)]
print results

提供

[{'rashod': 0.0, 'prihod': 100.0, 'prod_name': 'c', 'prod_hola': 'f'},
 {'rashod': 0.0, 'prihod': 1500.0, 'prod_name': 'a', 'prod_hola': 'b'},
 {'rashod': 0.0, 'prihod': 460.0, 'prod_name': 'r', 'prod_hola': 't'}]

0
这是一个解决方案,它使用一个临时的字典,其键基于输入字典的键值对,其中值为str类型。
def get_key(d):
    return {k: v for k, v in d.items() if isinstance(v, str)}

def sum_dicts(x, y):
    summed = {k: x.get(k, 0) + y[k] for k, v in y.items() if not isinstance(v, str)}
    summed.update(get_key(y))
    return summed

result = {}
for value in values:
    key = json.dumps(get_key(value))
    result[key] = sum_dicts(result.get(key, {}), value)

print result.values()

或者如果你想使用reduce()

def dict_sum_reducer(items, new):
    new_items = map(lambda x: sum_dicts(x, new) if get_key(x) == get_key(new) else x, items)
    if new_items == items:
        new_items.append(new)
    return new_items

print reduce(dict_sum_reducer, values, [])

感谢您的回答。这些答案真的很有帮助,让我学到了很多东西。 - Marin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接