2010-01-14 78 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) 
相關問題