繁体   English   中英

Python 3:合并具有不同属性的对象列表

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM