根据键值对匹配添加两个词典列表的元素

时间:2016-07-28 05:43:45

标签: python list

给定n个列表,其中包含m个词典作为其元素,我想生成一个新列表,其中包含一组连接的词典。

l1 = [{"index":'a', "b":2,'c':9}, {"index":'b', "b":3,"c":5}, {"index":'c', "b":8,"c":8}]
l2 = [{"index":'a', "b":4,'c':8}, {"index":'b', "b":9,"c":10},{"index":None, "b":11,"c":10}]

我想制作一个联合名单:

l3 = [{"index":'a', "b":6, "c":17}, 
     {"index":'b', "b":12, "c":15}, 
     {"index":'c', "b":8, "c":8},
     {"index":None, "b":11,"c":10}]

我有一个可以合并两个列表的方法。但正如您在上面所看到的,我也想添加这些元素。

def merge_lists(l1, l2, key):
merged = {}
for item in l1+l2:
  if item[key] in merged:
    merged[item[key]].update(item)
  else:
    merged[item[key]] = item
return [val for (_, val) in merged.items()]

l3 = merge_lists(l1,l2,'index')

在Python中执行此操作的最有效方法是什么?

1 个答案:

答案 0 :(得分:4)

你可以很容易地使用Counter这样的东西......

from collections import defaultdict, Counter

def merge_lists(l1, l2):
    d = defaultdict(Counter)
    for sdict in l1 + l2:
        counter = Counter(sdict)
        d[counter.pop('index')] += counter    

    lists = []
    for k, v in d.items():
        result = dict(v)
        result['index'] = k
        lists.append(result)
    return lists

l1 = [{"index":'a', "b":2,'c':9}, {"index":'b', "b":3,"c":5}, {"index":'c', "b":8,"c":8}]
l2 = [{"index":'a', "b":4,'c':8}, {"index":'b', "b":9,"c":10},{"index":None, "b":11,"c":10}]
print(merge_lists(l1, l2))

添加Counter实例的好处在于它几乎可以满足您的期望。如果一个计数器没有密钥,它就不会对总和添加任何内容,但如果两个计数器都有给定的密钥,那么它们的值将被添加并用作该密钥的结果值。

请注意,合并列表的顺序是任意的(基于defaultdict的顺序)。如果您需要以某种方式保留订单,可以在事后sort或创建默认的有序字典,该字典会根据indexl1的首次显示时间保留订单或l2

class DefaultOrderedDict(collections.OrderedDict):

    def __init__(self, default_factory, *args, **kwargs):
        self.default_factory = default_factory
        super(DefaultOrderedDict, self).__init__(*args, **kwargs)

    def __missing__(self, key):
        self[key] = self.default_factory()
        return self[key]

(在ActiveState和StackOverflow上有更多“完整”的默认有序字符,但是这个简单的 应该可以解决您手头的问题)