[英]Python 3: Merging list of objects with different attributes given
我有一种情况(下面是简化的基本示例),其中我有两个列表,其中包含具有不同属性的自定义对象。 在一个列表中,给出了一个属性(另一个是 0 或 None 或空列表),另一个列表包含另一个属性的值。 这两个列表不一定一样长,即可能有一些不匹配的条目。 我喜欢的是一个新列表(或修改现有列表之一),其中包含所有唯一对象,其属性值取自给定它的任何位置。
class human:
def __init__(self, name, age=0, height=0):
self.name = name
self.age = age
self.height = height
list_1 = [human("Alice", age=25), human("Bob", age=30), human("Steve", age=21)]
list_2 = [human("Alice", height=170), human("Bob", height=185)]
complete_list = merge(list_1, list_2)
所需的 output 将是一个等于的列表:
complete_list = [human("Alice", age=25, height=170), human("Bob", age=30, height=185), human("Steve", age=21)]
当然,我可以遍历两个列表并检查匹配项,然后检查我的值在哪里,然后更新它不在的地方等等,但这很丑不是吗?
您的代码假定名称是唯一的,我们可以利用这一点:
class human:
def __init__(self, name, age=0, height=0):
self.name = name
self.age = age
self.height = height
def merge(self, other):
if not self.age:
self.age = other.age
if not self.height:
self.height = other.height
def __repr__(self):
return 'human(name={}, age={}, height={})'.format(self.name, self.age, self.height)
def merge_lists(list_1, list_2):
output = {h.name: h for h in list_1}
for h in list_2:
try:
output[h.name].merge(h)
except KeyError:
output[h.name] = h
return list(output.values())
list_1 = [human("Alice", age=25), human("Bob", age=30), human("Steve", age=21)]
list_2 = [human("Alice", height=170), human("Bob", height=185)]
print(merge_lists(list_1, list_2))
输出
[human(name=Alice, age=25, height=170),
human(name=Bob, age=30, height=185),
human(name=Steve, age=21, height=0)]
如果我们实现一个HumanList
class,这可以更进一步:
from collections import UserList
from copy import deepcopy
class human:
def __init__(self, name, age=0, height=0):
self.name = name
self.age = age
self.height = height
def merge(self, other):
if not self.age:
self.age = other.age
if not self.height:
self.height = other.height
def __repr__(self):
return 'human(name={}, age={}, height={})'.format(self.name, self.age, self.height)
class HumanList(UserList):
def merge_lists(self, other_list):
output = {h.name: deepcopy(h) for h in self}
for h in other_list:
try:
output[h.name].merge(h)
except KeyError:
output[h.name] = h
return HumanList(output.values())
list_1 = HumanList([human("Alice", age=25), human("Bob", age=30), human("Steve", age=21)])
list_2 = HumanList([human("Alice", height=170), human("Bob", height=185)])
merged_list = list_1.merge_lists(list_2)
print(merged_list)
输出
[human(name=Alice, age=25, height=170),
human(name=Bob, age=30, height=185),
human(name=Steve, age=21, height=0)]
class human:
def __init__(self, name, age=0, height=0):
self.name = name
self.age = age
self.height = height
list_1 = [human("Alice", age=25), human("Bob", age=30), human("Steve", age=21)]
list_2 = [human("Alice", height=170), human("Bob", height=185)]
def merge(lst1, lst2):
d = {}
for h in lst1:
d[h.name] = {'age': h.age}
for h in lst2:
d[h.name].update({'height': h.height})
return d
merge(list_1, list_2)
回报:
{'Alice': {'age': 25, 'height': 170}, 'Bob': {'age': 30, 'height': 185}, 'Steve': {'age': 21}}
然后,您可以从字典中创建一个列表以转换为人类列表。
humans_dict = merge(list_1, list_2)
humans_lst = [human(k, v.get('age', 0), v.get('height', 0)) for k, v in d.items()]
您的问题缺少的是您按人名对不同的条目进行分组。
我会这样解决它:
people = dict()
for l in [list_1,list_2]:
for h in l:
if h.name not in people:
people[h.name] = h
else:
existingPerson = people[h.name]
if h.age:
existingPerson.age = h.age
if h.height:
existingPerson.height = h.height
如果你有很多属性,我会这样做:
people = dict()
for l in [list_1,list_2]:
for h in l:
if h.name not in people:
people[h.name] = h
else:
existingPerson = people[h.name]
for a in ['age','height']:
v = getattr(h,a)
if v:
setattr(existingPerson,a,v)
最后创建完整列表:
complete_list = list(people.values())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.