Python 将重复的字典项转换为具有ID数组的唯一项

Python 将重复的字典项转换为具有ID数组的唯一项,python,dictionary,Python,Dictionary,我有一个字典列表,其中一个字典值name包含我想要规范化的重复数据。列表如下所示: [ {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 8}, {'name': 'None on file', 'document_id': 40, 'annotation_id': 5}, {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 9}

我有一个字典列表,其中一个字典值
name
包含我想要规范化的重复数据。列表如下所示:

[
    {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 8}, 
    {'name': 'None on file', 'document_id': 40, 'annotation_id': 5},
    {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 9},
    {'name': 'Western Union', 'document_id': 61, 'annotation_id': 11}
]
我想做的是创建一个只包含唯一名称的新词典。但是我需要跟踪文档ID和注释ID。有时文档ID是相同的,但我只需要跟踪它们与名称的关联。因此,上述清单将变成:

[
     {'name': 'Craig McKray', 'document_ids': [50], 'annotation_ids': [8, 9]},
     {'name': 'None on file', 'document_ids': [40], 'annotation_id': [5]},
     {'name': 'Western Union', 'document_ids': [61], 'annotation_ids': [11]}
]
以下是我迄今为止尝试过的代码:

result = []
# resolve duplicate names
result_row = defaultdict(list)
for item in data:
    for double in data:
        if item['name'] == double['name']:
            result_row['name'] = item['name']
            result_row['record_ids'].append(item['document_id'])
            result_row['annotation_ids'].append(item['annotation_id'])
            result.append(result_row)
代码的主要问题是,我正在比较和查找重复项,但当我迭代到下一项时,它会再次找到重复项,从而创建某种程度上的无限循环。我如何编辑代码,使其不必反复比较重复的代码

new = dict()
for x in people:
    if x['name'] in new:
        new[x['name']].append({'document_id': x['document_id'], 'annotation_id': x['annotation_id']})
    else:
        new[x['name']] = [{'document_id': x['document_id'], 'annotation_id': x['annotation_id']}]
这不完全是你想要的,但是格式应该做你想要做的

这是输出:

{'Craig McKray': [{'annotation_id': 8, 'document_id': 50}, {'annotation_id': 9, 'document_id': 50}], 'Western Union': [{'annotation_id': 11, 'document_id': 61}], 'None on file': [{'annotation_id': 5, 'document_id': 40}]}
在这里,我认为这对你来说可能更好:

from collections import defaultdict
new = defaultdict(dict)

for x in people:
    if x['name'] in new:
        new[x['name']]['document_ids'].append(x['document_id'])
        new[x['name']]['annotation_ids'].append(x['annotation_id'])
    else:
        new[x['name']]['document_ids'] = [x['document_id']]
        new[x['name']]['annotation_ids'] = [x['annotation_id']]

一种更实用的
itertools.groupby
方法可能是这样的。这有点神秘,我来解释

from itertools import groupby
from operator import itemgetter

inp = [
    {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 8}, 
    {'name': 'None on file', 'document_id': 40, 'annotation_id': 5},
    {'name': 'Craig McKray', 'document_id': 50, 'annotation_id': 9},
    {'name': 'Western Union', 'document_id': 61, 'annotation_id': 11}
]

def groupvals(vals):

    namegetter = itemgetter('name')
    doccanngetter = itemgetter('document_id', 'annotation_id')

    for grouper, grps in groupby(sorted(vals, key=namegetter), key=namegetter):

        docanns = [set(param) for param in zip(*(doccanngetter(g) for g in grps))]
        yield {'name': grouper, 'document_id': list(docanns[0]), 'annotation_id': list(docanns[1])}


for result in groupvals(inp):
    print(result)
要使用
groupby
,您需要一个排序列表。所以首先按名字排序。然后是
groupby
name。接下来,您可以拉出
文档id
注释id
参数并将其压缩。这会将所有
文档id
放在一个列表中,将所有
注释id
放在另一个列表中。然后可以调用
set
删除重复项,并使用生成器将每个元素生成为
dict


我使用了一个生成器,因为它避免了建立结果列表的需要。尽管你可以这样做,如果你愿意。

我对这个主题的看法:

result = []
# resolve duplicate names
all_names = []
for i, item in enumerate(data):
    if item['name'] in all_names:
        continue
    result_row = {'name': item['name'], 'record_ids': [item['document_id']],
                  'annotation_ids':[item['annotation_id']]}
    all_names.append(item['name'])
    for j, double in enumerate(data):
        if item['name'] == double['name'] and i != j:
            result_row['record_ids'].append(double['document_id'])
            result_row['annotation_ids'].append(double['annotation_id'])
        result.append(result_row)
另一种选择:

from collections import defaultdict

catalog = defaultdict(lambda: defaultdict(list))

for d in dicts:
    entry = catalog[d['name']]
    for k in set(d) - {'name'}:
        entry[k].append(d[k])
漂亮的印花

>>> for name, e in catalog.items():
>>>     print "'{0}': {1}".format(name, e)

'Craig McKray': defaultdict(<type 'list'>, {'annotation_id': [8, 9], 'document_id': [50, 50]})
'Western Union': defaultdict(<type 'list'>, {'annotation_id': [11], 'document_id': [61]})
'None on file': defaultdict(<type 'list'>, {'annotation_id': [5], 'document_id': [40]})
>对于名称,e在catalog.items()中:
>>>打印“{0}”:{1}”。格式(名称,e)
“Craig McKray”:defaultdict(,{'annotation_id':[8,9],'document_id':[50,50]})
“西联”:defaultdict(,{'annotation_id':[11],'document_id':[61]})
“文件中无”:defaultdict(,{'annotation_id':[5],'document_id':[40]})

请发布您获得的输出。这很好,但defaultdict在这种情况下如何工作?对于我自己的教育。我们需要一个默认的dict,dict是默认的,这样我们就可以添加
注释\u id
键,然后给它分配一个列表。