2017-07-18 7 views
1

辞書の値がnameのいずれかで正規化するデータのリストがあります。リストは次のようになります。辞書の項目を重複してIDの配列を持つユニークなアイテムに変換する

[ 
    {'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} 
] 

私がしたいのは、一意の名前だけを含む新しい辞書を作成することです。しかし、私はdocument_idsとannotation_idsを追跡する必要があります。ドキュメントIDは同じであることもありますが、名前に関連付けられたものだけをトラッキングする必要があります。ときに私

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) 

コードの主な問題は、私が比較して重複を見つけるのですが、以下は

[ 
    {'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]} 
] 

は、私がこれまで試してみましたコードです:だから上記のリストはに変わるだろう次のアイテムに反復すると、重複したループが再度生成され、無限ループが生成されます。重複を何度も何度も比較しないようにコードを編集するにはどうすればよいですか?

+0

あなたが取得している出力を投稿してください。 – perigon

答えて

1
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']] 
+0

これは素晴らしいですが、このシナリオではdefaultdictはどのように機能しますか?私自身の教育のため。 – Casey

+1

デフォルトのdictを持つdefaultdictが必要です。そのため、 'annotation_ids'キーを追加してそれにリストを割り当てることができます。 –

0

より機能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の名前。次に、document_idannotation_idのパラメータを引き出し、それらを圧縮することができます。これは、すべてのdocument_idsをリストに入れ、すべてをannotation_idを別のものに入れるという効果があります。 setを呼び出して重複を削除し、ジェネレータを使用して各要素をdictとして生成することができます。

私は結果リストを構築する必要がないので、ジェネレータを使用しました。あなたが望むなら、あなたはそれをすることができます。

0

テーマに関する私の感想:

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) 
0

別のオプション:

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]}) 
関連する問題