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和处理这样的数据结构都很陌生.
尽量避免使用复杂的嵌套数据结构.我相信只有在他们集中使用数据结构时,人们才倾向于使用它们.程序完成后,或者搁置一段时间后,数据结构很快变得神秘.
对象可用于以更合理,更有条理的方式保留甚至为数据结构添加丰富性.例如,它的出现item和price总是一起去.因此,两个数据也可以在一个对象中配对:
class Item(object):
def __init__(self,name,price):
self.name=name
self.price=price
Run Code Online (Sandbox Code Playgroud)
同样,一个人似乎拥有一套id和name一套财产:
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)