【问题标题】:Python Count Elements in a List of Objects with Matching AttributesPython 计算具有匹配属性的对象列表中的元素
【发布时间】:2013-05-09 06:30:01
【问题描述】:

我正在尝试找到一种简单快速的方法来计算列表中符合条件的对象数量。 例如

class Person:
    def __init__(self, Name, Age, Gender):
        self.Name = Name
        self.Age = Age
        self.Gender = Gender

# List of People
PeopleList = [Person("Joan", 15, "F"), 
              Person("Henry", 18, "M"), 
              Person("Marg", 21, "F")]

现在,根据属性计算列表中与参数匹配的对象数量的最简单函数是什么? 例如,为 Person.Gender == "F" 或 Person.Age

【问题讨论】:

    标签: python list object attributes count


    【解决方案1】:
    class Person:
        def __init__(self, Name, Age, Gender):
            self.Name = Name
            self.Age = Age
            self.Gender = Gender
    
    
    >>> PeopleList = [Person("Joan", 15, "F"), 
                  Person("Henry", 18, "M"), 
                  Person("Marg", 21, "F")]
    >>> sum(p.Gender == "F" for p in PeopleList)
    2
    >>> sum(p.Age < 20 for p in PeopleList)
    2
    

    【讨论】:

    • 我更喜欢sum(1 for p in PeopleList if p.Gender == "F"),因为它不会滥用 bool 子类 int.
    • 我在这里必须同意@wim。即使是一名长期的 Python 程序员,我也花了一段时间来评估 sum 语句所做的事情。我发现sum(1 for p in PeopleList if p.Gender == "F") 更明确。
    • 但不是很清楚。也许计算机科学人员和那些在 bool 甚至还没有出现在语言中之前就一直在使用 python 的人很清楚,但对于具有数学头脑的人来说,“真”和“数字 1”在概念上是非常不同的对象,这并不明显。条件的总和是心理上的绊脚石,与阅读直接理解相比,它需要额外的思考时间。
    • @monkut Guido States 使用 FalseTrue 作为列表索引非常好。他还说了其他这样清晰的成语。这也是FalseTrue的明确用法
    【解决方案2】:

    我知道这是一个老问题,但现在一种 stdlib 方法是

    from collections import Counter
    
    c = Counter(getattr(person, 'gender') for person in PeopleList)
    # c now is a map of attribute values to counts -- eg: c['F']
    

    【讨论】:

    • 你为什么使用getattr(person, 'gender') 而不是简单的person.gender?这是不必要和多余的
    • @jamylak 好点。我真的不记得了。我可能在考虑动态选择的属性。例如:c = { attr: Counter(getattr(person, attr) for person in PeopleList) for attr in ['Name', 'Age', 'Gender'] }c 现在是属性到值计数器的映射。编辑:我现在记得。就是这样,因为它evolved 那样:)
    • 感谢您的澄清,我可以看到。如果我们只是简单地计算每个属性但问题有示例,那么这是有道理的。例如。 Person.Age &lt; 20 不适合这个,最好是简单的if statement
    【解决方案3】:

    我发现使用列表推导式并获取其长度比使用 sum() 更快。

    根据my tests...

    len([p for p in PeopleList if p.Gender == 'F'])
    

    ...运行速度是...的 1.59 倍

    sum(p.Gender == "F" for p in PeopleList)
    

    【讨论】:

    • 不是一个公平的测试,除非您还测试 sum([p.Gender == "F" for p in PeopleList]) 并发布微小、中等和巨大数据的结果
    【解决方案4】:

    我更喜欢这个:

    def count(iterable):
        return sum(1 for _ in iterable)
    

    那么你可以这样使用它:

    femaleCount = count(p for p in PeopleList if p.Gender == "F")
    

    它很便宜(不会创建无用的列表等)并且完全可读(我会说比sum(1 for … if …)sum(p.Gender == "F" for …) 都好)。

    【讨论】:

      【解决方案5】:

      我个人认为定义一个函数比多次使用更简单:

      def count(seq, pred):
          return sum(1 for v in seq if pred(v))
      
      print(count(PeopleList, lambda p: p.Gender == "F"))
      print(count(PeopleList, lambda p: p.Age < 20))
      

      特别是如果您想重用查询。

      【讨论】:

      • 编辑:我明白了,我交换了“if”的位置。谢谢,已修复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-09
      • 1970-01-01
      • 2016-07-25
      相关资源
      最近更新 更多