2010-01-14 46 views
9

的Python福利局这里寻找一些帮助......python列表的dicts如何合并key:value的值是否相同?

对于类型的字典中像Python列表可变数目:

list_dicts = [ 
{'id':'001', 'name':'jim', 'item':'pencil', 'price':'0.99'}, 
{'id':'002', 'name':'mary', 'item':'book', 'price':'15.49'}, 
{'id':'002', 'name':'mary', 'item':'tape', 'price':'7.99'}, 
{'id':'003', 'name':'john', 'item':'pen', 'price':'3.49'}, 
{'id':'003', 'name':'john', 'item':'stapler', 'price':'9.49'}, 
{'id':'003', 'name':'john', 'item':'scissors', 'price':'12.99'}, 
] 

我试图找到组类型的字典的最佳方式,其中值关键的“ID”相等,则添加/合并任何唯一键:价值,创造类似类型的字典新的列表:到目前为止

list_dicts2 = [ 
{'id':'001', 'name':'jim', 'item1':'pencil', 'price1':'0.99'}, 
{'id':'002', 'name':'mary', 'item1':'book', 'price1':'15.49', 'item2':'tape', 'price2':'7.99'}, 
{'id':'003', 'name':'john', 'item1':'pen', 'price1':'3.49', 'item2':'stapler', 'price2':'9.49', 'item3':'scissors', 'price3':'12.99'}, 
] 

,我已经想通了如何分组列表与http://stardict.sourceforge.net/Dictionaries.php下载:

myList = itertools.groupby(list_dicts, operator.itemgetter('id')) 

但我有如何建立http://stardict.sourceforge.net/Dictionaries.php下载到的新的列表挣扎:

1)添加额外的键值,以具有相同的“ID”

第一字典实例2)设置“项目”和“价格”键的新名称(例如, “item1”,“item2”,“item3”)。这对我来说似乎笨重,有没有更好的办法?

3)循环每个“ID”配套建设了一个字符串后面输出

我选择返回传递一个字典的模板函数,其中的方便的,只是因为类型的字典的新列表通过描述性键设置变量很有帮助(有很多变量)。如果有更清晰简洁的方法来实现这一点,我会好奇学习。再一次,我对Python很陌生,并且在处理像这样的数据结构。

回答

9

尽量避免复杂的嵌套的数据结构。我相信人们倾向于在他们密集使用数据结构时倾向于 。 程序完成后,或者暂时搁置一会,数据结构快速 变得神秘。

对象可以用来保持数据结构,甚至以更加有条理的方式增加数据结构的丰富性。例如,看起来itemprice总是在一起。因此,数据的两片还不如在一个对象配对:

class Item(object): 
    def __init__(self,name,price): 
     self.name=name 
     self.price=price 

同样,一个人似乎有一个idname和一套财产:

class Person(object): 
    def __init__(self,id,name,*items): 
     self.id=id 
     self.name=name 
     self.items=set(items) 

如果买成使用类像这样的想法,那么你的list_dicts可能成为

list_people = [ 
    Person('001','jim',Item('pencil',0.99)), 
    Person('002','mary',Item('book',15.49)), 
    Person('002','mary',Item('tape',7.99)), 
    Person('003','john',Item('pen',3.49)), 
    Person('003','john',Item('stapler',9.49)), 
    Person('003','john',Item('scissors',12.99)), 
] 

然后,基于人合并210,你可以使用Python的reduce功能, 与take_items,这需要(合并)从一个人的项目一起,并让他们到另一个:

def take_items(person,other): 
    ''' 
    person takes other's items. 
    Note however, that although person may be altered, other remains the same -- 
    other does not lose its items.  
    ''' 
    person.items.update(other.items) 
    return person 

全部放在一起:

import itertools 
import operator 

class Item(object): 
    def __init__(self,name,price): 
     self.name=name 
     self.price=price 
    def __str__(self): 
     return '{0} {1}'.format(self.name,self.price) 

class Person(object): 
    def __init__(self,id,name,*items): 
     self.id=id 
     self.name=name 
     self.items=set(items) 
    def __str__(self): 
     return '{0} {1}: {2}'.format(self.id,self.name,map(str,self.items)) 

list_people = [ 
    Person('001','jim',Item('pencil',0.99)), 
    Person('002','mary',Item('book',15.49)), 
    Person('002','mary',Item('tape',7.99)), 
    Person('003','john',Item('pen',3.49)), 
    Person('003','john',Item('stapler',9.49)), 
    Person('003','john',Item('scissors',12.99)), 
] 

def take_items(person,other): 
    ''' 
    person takes other's items. 
    Note however, that although person may be altered, other remains the same -- 
    other does not lose its items.  
    ''' 
    person.items.update(other.items) 
    return person 

list_people2 = [reduce(take_items,g) 
       for k,g in itertools.groupby(list_people, lambda person: person.id)] 
for person in list_people2: 
    print(person) 
0

我想它会更容易在list_dicts的物品组合成的东西,看起来更像是这样的:

list_dicts2 = [{'id':1, 'name':'jim', 'items':[{'itemname':'pencil','price':'0.99'}], {'id':2, 'name':'mary', 'items':[{'itemname':'book','price':'15.49'}, {'itemname':'tape','price':'7.99'}]]

你也可以使用一个元组列表的“项目”或者一个名为元组。

0

这看起来非常像作业问题。

正如上面的海报提到的,有对这种数据的一些更合适的数据结构,在下面的一些变种可能是合理的:

[ ('001', 'jim', [('pencil', '0.99')]), 
('002', 'mary', [('book', '15.49'), ('tape', '7.99')]), 
('003', 'john', [('pen', '3.49'), ('stapler', '9.49'), ('scissors', '12.99')])] 

这可以用相对简单的进行:

list2 = [] 
for id,iter in itertools.groupby(list_dicts,operator.itemgetter('id')): 
    idList = list(iter) 
    list2.append((id,idList[0]['name'],[(z['item'],z['price']) for z in idList])) 

这个问题很有意思的一点是,在使用groupby时难以提取'name',而无法迭代该项目。

要返回到原来的目标,虽然,你可以使用这样的代码(如OP建议):

list3 = [] 
for id,name,itemList in list2: 
    newitem = dict({'id':id,'name':name}) 
    for index,items in enumerate(itemList): 
     newitem['item'+str(index+1)] = items[0] 
     newitem['price'+str(index+1)] = items[1] 
    list3.append(newitem) 
相关问题