在忽略某些键的同时在列表中查找重复映射的 Pythonic 方法,并将重复映射组合成一个新列表

Pythonic way of finding duplicate maps in a list while ignoring certain keys, and combining the duplicate maps to make a new list

我想编写一个接受以下输入的代码:

list (list of maps)
request_keys (list of strings)
operation (add,substract,multiply,concat)

该代码将查看地图列表,以查找除 request_keys 中给出的键之外的所有键都具有相同值的映射。在找到两个匹配搜索键值的映射后,代码将对两个映射执行操作(添加、乘法、减法、连接)并将它们组合成一个映射。这张组合图基本可以替代另外两张图

我已经编写了以下代码来执行此操作。该代码仅执行添加操作。可以扩展它以进行其他操作

In [83]: list
Out[83]: 
[{'a': 2, 'b': 3, 'c': 10},
 {'a': 2, 'b': 3, 'c': 3},
 {'a': 2, 'b': 4, 'c': 4},
 {'a': 2, 'b': 3, 'c': 2},
 {'a': 2, 'b': 3, 'c': 3}]

In [84]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def func(list,request_keys):
:    new_list = []
:    found_indexes = []
:    for i in range(0,len(list)):
:        new_item = list[i]
:        if i in found_indexes:
:            continue
:        for j in range(0,len(list)):
:            if i != j and {k: v for k,v in list[i].iteritems() if k not in request_keys} == {k: v for k,v in list[j].iteritems() if k not in request_keys}:
:                found_indexes.append(j)
:                for request_key in request_keys:
:                    new_item[request_key] += list[j][request_key]
:        new_list.append(new_item)
:    return new_list
:--

In [85]: func(list,['c'])
Out[85]: [{'a': 2, 'b': 3, 'c': 18}, {'a': 2, 'b': 4, 'c': 4}]

In [86]: 

我想知道的是,是否有更快、内存效率更高、更干净且更 pythonic 的方式来做同样的事情?

谢谢

您手动生成所有组合,然后比较每个组合。这很浪费。相反,我建议通过匹配键将字典分组到另一个字典中,然后添加 "same" 字典。另外,您忘记了 operator 参数。

import collections, operator, functools
def func(lst, request_keys, op=operator.add):
    matching_dicts = collections.defaultdict(list)
    for d in lst:
        key = tuple(sorted(((k, d[k]) for k in d if k not in request_keys)))
        matching_dicts[key].append(d)

    for group in matching_dicts.values():
        merged = dict(group[0])
        merged.update({key: functools.reduce(op, (g[key] for g in group)) 
                       for key in request_keys})
        yield merged

这是做什么的:首先,它创建一个字典,将两个字典必须相等的键值对映射到所有具有这些键值对的字典。然后它迭代这些组中的字典,使用该组中的一个作为原型并使用该组中所有字典的总和(或乘积,或其他,取决于运算符)更新它 required_keys .

请注意,这 return 是一个生成器。如果您想要一个列表,只需像 list(func(...)) 那样称呼它,或者在列表中累积 merged 个字典,然后 return 该列表。

from itertools import groupby
from operator import itemgetter

def mergeDic(inputData, request_keys):
    keys = inputData[0].keys()
    comparedKeys = [item for item in keys if item not in request_keys]
    grouper = itemgetter(*comparedKeys)
    result = []
    for key, grp in groupby(sorted(inputData, key = grouper), grouper):
        temp_dict = dict(zip(comparedKeys, key))
        for request_key in request_keys:
            temp_dict[request_key] = sum(item[request_key] for item in grp)
        result.append(temp_dict)
    return result

inputData = [{'a': 2, 'b': 3, 'c': 10},
 {'a': 2, 'b': 3, 'c': 3},
 {'a': 2, 'b': 4, 'c': 4},
 {'a': 2, 'b': 3, 'c': 2},
 {'a': 2, 'b': 3, 'c': 3}]
from pprint import pprint
pprint(mergeDic(inputData,['c']))