将列表中的类似词典合并在一起

时间:2012-10-05 21:09:35

标签: python dictionary

这里是python的新手。我一直在拉我的头发几个小时仍然无法解决这个问题。

我有一个词典列表:

[ {'FX0XST001.MID5': '195', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'}
  {'FX0XST001.MID13': '4929', 'Name': 'Firmicutes', 'Taxonomy ID': '1239','Type': 'phylum'},
  {'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'},
                                        .
                                        .
                                        .
                                        .

  {'FX0XST001.MID6': '125', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}
  {'FX0XST001.MID25': '70', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}
  {'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'} ]

我想根据类型,名称和分类标识

合并列表中的字典
  [ {'FX0XST001.MID5': '195', 'FX0XST001.MID13': '4929', 'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'}
                                        .
                                        .
                                        .
                                        .

    {'FX0XST001.MID6': '125', 'FX0XST001.MID25': '70', 'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}]

我有这样的数据结构设置,因为我需要稍后使用csv.DictWriter将数据写入CSV。

有人会指出我正确的方向吗?

4 个答案:

答案 0 :(得分:5)

您可以使用groupby函数:

http://docs.python.org/library/itertools.html#itertools.groupby

from itertools import groupby

keyfunc = lambda row : (row['Type'], row['Taxonomy ID'], row['Name'])

result = []

data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
    # you can either add the matching rows to the item so you end up with what you wanted
    item = {}        
    for row in g:
        item.update(row)
    result.append(item)

    # or you could just add the matched rows as subitems to a parent dictionary
    # which might come in handy if you need to work with just the parts that are
    # different
    item = {'Type': k[0], 'Taxonomy ID' : k[1], 'Name' : k[2], 'matches': [])
    for row in g:
        del row['Type']
        del row['Taxonomy ID']
        del row['Name']
        item['matches'].append(row)
    result.append(item)  

答案 1 :(得分:3)

制作一些测试数据:

list_of_dicts = [
                 {"Taxonomy ID":1, "Name":"Bob", "Type":"M", "hair":"brown", "eyes":"green"},
                 {"Taxonomy ID":1, "Name":"Bob", "Type":"M", "height":"6'2''", "weight":200},
                 {"Taxonomy ID":2, "Name":"Alice", "Type":"F", "hair":"black", "eyes":"hazel"},
                 {"Taxonomy ID":2, "Name":"Alice", "Type":"F", "height":"5'7''", "weight":145}
                ]    

我认为这(下面)是一个使用reduce的巧妙技巧,可以改进其他groupby解决方案。

import itertools
def key_func(elem):
    return (elem["Taxonomy ID"], elem["Name"], elem["Type"])

output_list_of_dicts = [reduce((lambda x,y: x.update(y) or x), list(val)) for key, val in itertools.groupby(list_of_dicts, key_func)]

然后打印输出:

for elem in output_list_of_dicts:
    print elem

打印:

{'eyes': 'green', 'Name': 'Bob', 'weight': 200, 'Taxonomy ID': 1, 'hair': 'brown', 'height': "6'2''", 'Type': 'M'}
{'eyes': 'hazel', 'Name': 'Alice', 'weight': 145, 'Taxonomy ID': 2, 'hair': 'black', 'height': "5'7''", 'Type': 'F'}

仅供参考,Python Pandas 更适合此类聚合,尤其是在处理.csv或.h5文件的文件I / O时,比itertools内容更好

答案 2 :(得分:2)

也许最简单的方法是创建一个新的字典,由(类型,名称,分类ID)元组索引,并迭代字典,存储值(类型,名称,分类ID)。使用默认的dict可以使这更容易。例如:

from collections import defaultdict
grouped = defaultdict(lambda : {})

# iterate over items and store:
for entry in list_of_dictionaries:
    grouped[(entry["Type"], entry["Name"], entry["Taxonomy ID"])].update(entry)

# now you have everything stored the way you want in values, and you don't
# need the dict anymore
grouped_entries = grouped.values()

这有点hackish,特别是因为你每次使用update时都会覆盖“Type”,“Name”和“Phylum”,但由于你的dict键是可变的,这可能是最好的你可以做。这将使您至少接近您所需要的。

更好的方法是在初始导入时执行此操作并跳过中间步骤(除非您事先需要转换数据)。另外,如果您可以进入唯一不同的字段,则可以将update更改为:grouped[(type, name, taxonomy_id)][key] = value其中键和值类似于:'FX0XST001.MID5','195'

答案 3 :(得分:0)

from itertools import groupby

data = [ {'FX0XST001.MID5': '195', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type':'phylum'},
  {'FX0XST001.MID13': '4929', 'Name': 'Firmicutes', 'Taxonomy ID': '1239','Type': 'phylum'},
  {'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'},
  {'FX0XST001.MID6': '125', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'},
  {'FX0XST001.MID25': '70', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'},
  {'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'} ,]

kk = ('Name', 'Taxonomy ID', 'Type')

def key(item): return tuple(item[k] for k in kk)

result = []
data = sorted(data, key=key)
for k, g in groupby(data, key):
    result.append(dict((i, j) for d in g for i,j in d.items()))


print result