按属性聚合对象数组

时间:2014-12-28 08:09:53

标签: python list dictionary

我有一个dicts列表,每个都有两个键/值对。我需要通过对第二个键的值进行求和来组合第一个键共享相同值的词组。例如:

[
    {'foo': 34, 'bar': 2}, 
    {'foo': 34, 'bar': 3}, 
    {'foo': 35, 'bar': 1}, 
    {'foo': 35, 'bar': 7}, 
    {'foo': 35, 'bar': 2}
]

会出现:

[
    {'foo': 34, 'bar': 5}, 
    {'foo': 35, 'bar': 10}
]

我编写了以下函数,该函数有效,但看起来非常冗长,我几乎可以肯定有一个很酷的pythonic技巧会更干净,性能更高。

def combine(arr):
    arr_out = []
    if arr:
        arr_out.append({'foo': arr[0]['foo'], 'bar': 0})
        for i in range(len(arr)):
            if arr[i]['foo'] == arr_out[-1]['foo']:
                arr_out[-1]['bar'] += arr[i]['bar']
            else:
                arr_out.append({'foo': arr[i]['foo'], 'bar': arr[i]['bar']})
    return arr_out

有人有任何建议吗?

3 个答案:

答案 0 :(得分:5)

使用itertools.groupby

>>> arr = [
...     {'foo': 34, 'bar': 2},
...     {'foo': 34, 'bar': 3},
...     {'foo': 35, 'bar': 1},
...     {'foo': 35, 'bar': 7},
...     {'foo': 35, 'bar': 2}
... ]
>>> import itertools
>>> key = lambda d: d['foo']
>>> [{'foo': key, 'bar': sum(d['bar'] for d in grp)}
...  for key, grp in itertools.groupby(sorted(arr, key=key), key=key)]
[{'foo': 34, 'bar': 5}, {'foo': 35, 'bar': 10}]

如果列表已经排序,您可以省略sorted电话:

>>> [{'foo': key, 'bar': sum(d['bar'] for d in grp)}
...  for key, grp in itertools.groupby(arr, key=key)]
[{'foo': 34, 'bar': 5}, {'foo': 35, 'bar': 10}]

答案 1 :(得分:3)

  1. 根据bar值对foo值进行分组并添加。

    >>> grouper = {}
    >>> for d in data:
    ...     grouper[d["foo"]] = grouper.get(d["foo"], 0) + d["bar"]
    ... 
    >>> grouper
    {34: 5, 35: 10}
    
  2. 然后用列表理解重建dicts列表,就像这样

    >>> [{"foo": item, "bar": grouper[item]} for item in grouper]
    [{'foo': 34, 'bar': 5}, {'foo': 35, 'bar': 10}]
    

答案 2 :(得分:0)

此解决方案使用collections.defaultdict

def combine(arr):
    c = collections.defaultdict(int)
    for i in arr:
        c[i['foo']] += i['bar']
    # c == {34: 5, 35: 10}

    return [{'foo': k, 'bar': c[k]} for k in sorted(c)]

字典c是默认字典,值为' foo'作为' bar'的关键和价值。作为价值。