按键合并词典列表的更好方法

时间:2014-07-18 17:49:23

标签: python python-2.7

我有一个字典列表和一个可以从列表中的每个字典中提取值的函数。目标是我得到一个字典,其中键是给定函数返回的值,当我从给定的字典列表中传递字典时。返回字典中的相应值应该是原始字典列表中的字典子集,给定函数返回相应的键。

我知道这个解释非常令人困惑,所以我在一个实现中展示它:

keygen = lambda x: x['key']

data = [{'key': 'key1',
         'data': 'value2'},
        {'key': 'key3',
         'data': 'value2'},
        {'key': 'key2',
         'data': 'value2'},
        {'key': 'key2',
         'data': 'value2'},
        {'key': 'key1',
         'data': 'value2'}]

def merge_by_keygen(data, keygen):
    return_value = {} 
    for dataset in data:
        if keygen(dataset) not in return_value.keys():
            return_value[keygen(dataset)] = [] 
        return_value[keygen(dataset)].append(dataset)
    return return_value

merge_by_keygen(data, keygen)

返回:

{'key3': [{'data': 'value2', 'key': 'key3'}], 
 'key2': [{'data': 'value2', 'key': 'key2'}, {'data': 'value2', 'key': 'key2'}], 
 'key1': [{'data': 'value2', 'key': 'key1'}, {'data': 'value2', 'key': 'key1'}]}

我正在寻找相同逻辑的更好,更紧凑的实现,比如一些字典/列表推导。谢谢!

4 个答案:

答案 0 :(得分:5)

这是由itertools.groupby

处理的理想问题

<强>实施

from itertools import groupby
from operator import itemgetter
groups = groupby(sorted(data, key = itemgetter('key')), key = itemgetter('key'))
data_dict = {k : list(g) for k, g in groups}

或者如果您更喜欢单行

data_dict = {k : list(g) 
             for k, g in groupby(sorted(data, 
                                        key = itemgetter('key')), 
                                 key = itemgetter('key'))}

<强>输出

{'key1': [{'data': 'value2', 'key': 'key1'},
          {'data': 'value2', 'key': 'key1'}],
 'key2': [{'data': 'value2', 'key': 'key2'},
          {'data': 'value2', 'key': 'key2'}],
 'key3': [{'data': 'value2', 'key': 'key3'}]}

答案 1 :(得分:2)

如果您不介意使用第三方软件包,可以使用toolz.groupby轻松完成:

>>> import toolz
>>> toolz.groupby(keygen, data)
{'key1': [{'data': 'value2', 'key': 'key1'},
          {'data': 'value2', 'key': 'key1'}],
 'key2': [{'data': 'value2', 'key': 'key2'},
          {'data': 'value2', 'key': 'key2'}],
 'key3': [{'data': 'value2', 'key': 'key3'}]}

使用toolz.groupby('key', data)

也可获得相同的结果

答案 2 :(得分:1)

我不认为这是理解的,但你可以使用collections.defaultdict(list)实例使它更整洁:

import collections

def merge_by_keygen(data, keygen):
    return_value = collections.defaultdict(list)
    for dataset in data:
        key = keygen(dataset)
        return_value[key].append(dataset)
    return return_value

对我来说这看起来很干净 - 如果你愿意的话,你可以在你调用keygen功能的地方移动,但我认为你可能会失去清晰度。

答案 3 :(得分:0)

我认为这样做

return_value = {}
for d in data:
    return_value.setdefault(keygen(d), []).append(d)

你可以用列表理解来编写它,但是使用列表推导的副作用来影响数据,然后建立一个无结果列表然后扔掉它是很难看的......

r = {}
[r.setdefault(keygen(d), []).append(d) for d in data]

你的函数的核心都归结为dictionary setdefault方法。关于调用keygen的所有三行,检查键是否在返回字典中,如果它不创建空列表,将空列表存储在字典中,然后再次查询字典以使列表准备好附加到它 - 全部由setdefault()完成。