python的dicts列表如何合并键:值相同的值?

abr*_*brg 9 python merge dictionary list

Python newb在这里寻求一些帮助......

对于python列表中可变数量的dicts,如:

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'},
]
Run Code Online (Sandbox Code Playgroud)

我正在尝试找到将键"id"的值相等的分组的最佳方法,然后添加/合并任何唯一键:value并创建一个新的dicts列表,如:

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'},
]
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经想出如何将列表中的dicts分组为:

myList = itertools.groupby(list_dicts, operator.itemgetter('id'))
Run Code Online (Sandbox Code Playgroud)

但我正在努力构建新的dicts列表:

1)将额外的键和值添加到具有相同"id"的第一个dict实例

2)为"item"和"price"键设置新名称(例如"item1","item2","item3").这对我来说似乎很笨拙,还有更好的方法吗?

3)遍历每个"id"匹配以构建一个字符串以便以后输出

我选择返回一个新的dicts列表只是因为将dict传递给模板函数的便利性,其中通过描述性键设置变量是有帮助的(有很多变量).如果有更简洁的方法来实现这一点,我很想学习.同样,我对Python和处理这样的数据结构都很陌生.

unu*_*tbu 9

尽量避免使用复杂的嵌套数据结构.我相信只有在他们集中使用数据结构时,人们才倾向于使用它们.程序完成后,或者搁置一段时间后,数据结构很快变得神秘.

对象可用于以更合理,更有条理的方式保留甚至为数据结构添加丰富性.例如,它的出现itemprice总是一起去.因此,两个数据也可以在一个对象中配对:

class Item(object):
    def __init__(self,name,price):
        self.name=name
        self.price=price
Run Code Online (Sandbox Code Playgroud)

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

class Person(object):
    def __init__(self,id,name,*items):
        self.id=id
        self.name=name
        self.items=set(items)
Run Code Online (Sandbox Code Playgroud)

如果你购买使用这些类的想法,那么你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)), 
]
Run Code Online (Sandbox Code Playgroud)

然后,为了合并基于的人id,你可以使用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
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

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)
Run Code Online (Sandbox Code Playgroud)