【问题标题】:How can I iterate over a list with two different criteria?如何迭代具有两个不同标准的列表?
【发布时间】:2019-11-01 07:37:06
【问题描述】:

大家好,我遇到了一个 for 循环问题,我无法在线找到解决方案。

假设我创建了两个类,一个用于人,一个用于动物。通过为动物类设置一个循环方法,它遍历一个人的年龄列表,我想找到每只具有相同年龄或至少最小年龄差距的宠物的主人(这个例子只是为了让代码看起来更简单)。我使用了min() 函数来找到年龄差距最小的人,这很好。

但是,如果我在选择过程中再添加一个标准呢?例如,我只想将动物分配给那些拥有少于 3 只宠物的人,这意味着即使一个人的年龄差距最小,如果该人已经拥有 3 只宠物,则无法将宠物分配给该人。在这种情况下,循环必须找到下一个拥有少于 3 只宠物的年龄差距最小的人。在我的情况下,必须将 A1 分配给 P1,因为它是拥有少于 3 只宠物的年龄差距最小的人。

到目前为止,这是我的代码:

class People:
    def __init__(self, name, age, pets_owned):
        self.name=name
        self.age=age
        self.pets_owned=pets_owned

P1=People("John",16, 1)
P2=People("Alex",10, 4)
P3=People("Anna", 20, 3)


People_List=[P1, P2, P3]
People_Age=[P1.age, P2.age, P3.age]

class Animal:
    def __init__(self, name, age, owner):
        self.name=name
        self.age=age
        self.owner=owner

    def find(self):
        closest_age = (min(People_Age, key=lambda x: abs(x - self.age)))
        for a in People_List:
            if a.age ==closest_age and a.pets_owned<3:
                self.owner=a.name
                a.pets_owned+=1
                break

            elif a.age==closest_age and a.pets_owned >=3:
                pass #this is where I`m stuck


        print(self.owner)


A1=Animal("Snoopy",7,"not_owned_yet")


A1.find()

【问题讨论】:

    标签: python list class for-loop minimum


    【解决方案1】:

    如果您知道由于某个条件而不会包括某些人,我会预先过滤传入列表以排除这些人。基本上,根本不用 for 循环,只需过滤列表,然后找到最小值,然后添加宠物。

    class People:
        def __init__(self, name, age, pets_owned):
            self.name=name
            self.age=age
            self.pets_owned=pets_owned
    
    P1=People("John",16, 1)
    P2=People("Alex",10, 4)
    P3=People("Anna", 20, 3)
    
    
    People_List=[P1, P2, P3]
    People_Age=[P1.age, P2.age, P3.age]
    
    class Animal:
        def __init__(self, name, age, owner):
            self.name=name
            self.age=age
            self.owner=owner
    
        def find(self):
            people_with_less_than_3 = filter(lambda x: x.pets_owned<3, People_List) # filter the list to only include people that have less than 3 pets
            try:
                person_with_closest_age = min(people_with_less_than_3, key=lambda x: abs(x.age - self.age)) # change this to return a person as well
            except:
                # do something if no person with < 3 pets
            self.owner = person_with_closest_age.name
            print(self.owner)
    
    
    A1=Animal("Snoopy",7,"not_owned_yet")
    
    
    A1.find()
    

    【讨论】:

    • 在 find 的第一行删除list 转换,您在 Python 3 上的解决方案将返回最佳状态(列表中的单遍而不是 2 个最坏的情况)——这正是生成器大放异彩的地方。
    • @kabanus 不错,prolly 应该在没有 people_with_less_than_3 时添加一个条件,但是 OP 应该决定在这种情况下该怎么做
    • 非常感谢瑞恩的帮助。非常简单的答案!
    【解决方案2】:

    您可以根据多个属性进行排序,方法是让您的排序键返回一个元组。在我的示例中,我们首先根据年龄差距(优先级较高)进行排序,然后根据拥有的宠物数量(优先级较低)进行排序。您不需要像我一样使用sorted,因为我只是用它来演示如何基于多个属性进行排序。您可能希望将min 与相同的密钥一起使用以获得最符合条件的人。您还需要修改 assign_new_owner 以实际分配新所有者而不是(使用 min)而不是打印人员:

    class Person:
    
        def __init__(self, name, age, pets_owned):
            self.name = name
            self.age = age
            self.pets_owned = pets_owned
    
        def __str__(self):
            return f"{self.name}, age {self.age} owns {self.pets_owned} pet(s)."
    
    class Animal:
    
        def __init__(self, name, age, owner=None):
            self.name = name
            self.age = age
            self.owner = owner
    
        def assign_new_owner(self, people):
            sorted_people = sorted(people, key=lambda p: (abs(p.age - self.age), p.pets_owned))
            for person in sorted_people:
                print(person)
    
    def main():
    
        people = [
            Person("Alex", 16, 0),
            Person("Nigel", 15, 2),
            Person("Fred", 10, 3),
            Person("Tom", 10, 0),
            Person("Tyler", 15, 0),
            Person("Sam", 15, 1)
            ]
    
        animal = Animal("Snoopy", 10)
        animal.assign_new_owner(people)
    
        return 0
    
    if __name__ == "__main__":
        import sys
        sys.exit(main())
    

    输出:

     Tom, age 10 owns 0 pet(s).
     Fred, age 10 owns 3 pet(s).
     Tyler, age 15 owns 0 pet(s).
     Sam, age 15 owns 1 pet(s).
     Nigel, age 15 owns 2 pet(s).
     Alex, age 16 owns 0 pet(s).
    

    编辑:使用 min 后,代码可能看起来更像这样:

    class Person:
    
        def __init__(self, name, age, pets_owned):
            self.name = name
            self.age = age
            self.pets_owned = pets_owned
    
        def __str__(self):
            return f"{self.name}, age {self.age} owns {self.pets_owned} pet(s)."
    
    class Animal:
    
        def __init__(self, name, age, owner=None):
            self.name = name
            self.age = age
            self.owner = owner
    
        def __str__(self):
            return f"{self.name}, age {self.age} is owned by {self.owner.name if self.owner else 'no one'}."
    
        def assign_new_owner(self, people):
            self.owner = min(people, key=lambda p: (abs(p.age - self.age), p.pets_owned))
    
    def main():
    
        people = [
            Person("Alex", 16, 0),
            Person("Nigel", 15, 2),
            Person("Fred", 10, 3),
            Person("Tom", 10, 0),
            Person("Tyler", 15, 0),
            Person("Sam", 15, 1)
            ]
    
        animal = Animal("Snoopy", 10)
        print(animal)
        animal.assign_new_owner(people)
        print(animal)
    
        return 0
    
    if __name__ == "__main__":
        import sys
        sys.exit(main())
    

    输出:

    Snoopy, age 10 is owned by no one.
    Snoopy, age 10 is owned by Tom.
    

    【讨论】:

      猜你喜欢
      • 2022-11-03
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-23
      相关资源
      最近更新 更多