【问题标题】:How do I get the number of lists with a particular element?如何获取具有特定元素的列表数量?
【发布时间】:2017-02-17 20:54:34
【问题描述】:

我有一个列表,看起来像

listOfLists = [
    ['a','b','c','d'],
    ['a','b'],
    ['a','c'],
    ['c','c','c','c']  
 ] 

我想计算具有特定元素的列表的数量。例如,我的输出应该是

{'a':3,'b':2,'c':3,'d':1}

如您所见,我不需要元素的总数。在"c" 的情况下,虽然其总数为 5,但输出为 3,因为它只出现在 3 个列表中。

我正在使用计数器来获取计数。如下所示。

line_count_tags = []
for lists in lists_of_lists:
    s = set()
    for element in lists:
         s.add(t)
    lines_count_tags.append(list(s))

count = Counter([count for counts in lines_count_tags for count in counts])

所以,当我打印计数时,我得到了

{'a':3,'c':3,'b':2,'d':1}

我想知道是否有更好的方法来实现我的目标。

【问题讨论】:

    标签: python list python-3.x counting


    【解决方案1】:

    使用Counter 并将每个列表转换为一个集合。 set 将从每个列表中删除所有重复项,这样您就不会计算同一列表中的重复值:

    >>> from collections import Counter
    
    >>> Counter(item for lst in listOfLists for item in set(lst))
    Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
    

    如果您喜欢函数式编程,您还可以将chainset-mapped listOfLists 提供给Counter

    >>> from collections import Counter
    >>> from itertools import chain
    
    >>> Counter(chain.from_iterable(map(set, listOfLists)))
    Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
    

    这与第一种方法完全等效(除了可能更快一点)。

    【讨论】:

      【解决方案2】:

      我会将每个列表转换为一个集合,然后再计算传递给Counter 的生成器理解:

      import collections
      print(collections.Counter(y for x in listOfLists for y in set(x)))
      

      结果:

      Counter({'a': 3, 'c': 3, 'b': 2, 'd': 1})
      

      (这实际上是您所做的,但上面的代码缩短了很多循环和临时列表创建)

      【讨论】:

        【解决方案3】:

        你也可以不用Counter

        result = {}
        for lis in listOfLists:
            for element in set(lis):
                result[element] = result.get(element, 0) + 1
        print result  # {'a': 3, 'c': 3, 'b': 2, 'd': 1}
        

        不是最优雅的,但应该更快。

        【讨论】:

          【解决方案4】:

          Counter 方法与 itertools.chain.from_iterable 的风格差异可能看起来像

          Counter(chain.from_iterable(map(set, listOfLists)))
          

          演示

          >>> from itertools import chain
          >>> from collections import Counter
          >>> Counter(chain.from_iterable(map(set, listOfLists)))
          Counter({'a': 3, 'b': 2, 'c': 3, 'd': 1})
          

          粗略基准

          %timeit Counter(item for lst in listOfLists for item in set(lst))
          100000 loops, best of 3: 13.5 µs per loop
          
          %timeit Counter(chain.from_iterable(map(set, listOfLists)))
          100000 loops, best of 3: 12.4 µs per loop
          

          【讨论】:

          • 我在 CPython 2.7.11 上使用 itertools.chain (~40%!) 获得了更快的执行速度。尽管如此,Counter + itertools.chain 的执行速度比我介绍的 raw 方法慢 4 倍。
          • @zwer 嗯,取决于我们讨论的输入大小。我的解决方案有更多的开销,但如果你增加输入大小,它会更快。这就是为什么基准测试并不是很重要的原因:)
          • 没错,我只是对我所在位置的速度差异感到惊讶,我不习惯 itertools 实际上表现出色,嗯,几乎任何东西 - 它们通常速度较慢,但​​是更容易阅读的选择:D
          【解决方案5】:

          只需转换为set,使用itertools.chain.from_iterable 展平,然后输入Counter

          from collections import Counter
          from itertools import chain
          
          inp = [
              ['a','b','c','d'],
              ['a','b'],
              ['a','c'],
              ['c','c','c','c']  
           ] 
          
          
          print(Counter(chain.from_iterable(map(set, inp))))
          

          【讨论】:

            【解决方案6】:

            此方法使用集合推导计算 listOfLists 中的唯一条目,然后使用字典推导计算每个列表中的出现次数

            A = {val for s in listOfLists for val in s}
            d = {i: sum( i in j for j in listOfLists) for i in A}
            print(d) # {'a': 3, 'c': 3, 'b': 2, 'd': 1}
            

            我承认这有点难看,但它是一个可能的解决方案(以及字典理解的一个很酷的用法)。 您还可以通过将 A 的计算直接移到字典理解中来使其成为单行代码

            【讨论】:

            • 无需再次将您的集合A 转换为列表或使用列表理解提供集合,生成表达式更好...实际上您可以将A 构建为集合也理解
            • @Copperfield 感谢您的建议。我已经做出了改变。
            【解决方案7】:

            这是另一个使用循环的版本:

            listOfLists = [
                ['a','b','c','d'],
                ['a','b'],
                ['a','c'],
                ['c','c','c','c']
                ]
            
            final = {}
            for lst in listOfLists:
                for letter in lst:
                    if letter in final:
                        final[letter] += 1
                    else:
                        final[letter] = 1
            

            所以创建一个名为 final 的空字典。然后遍历每个列表的每个字母。如果字母在 final 作为键中还不存在,则创建一个新键和值 = 1。否则将该键的值加 1。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-02-13
              • 2013-09-06
              • 1970-01-01
              • 2014-05-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-17
              相关资源
              最近更新 更多