以优雅的方式计算嵌套列表中的元素

时间:2016-08-05 08:58:11

标签: python python-3.x

我在

列表中嵌套了元组
l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]

我想知道列表中有多少'a'和'b'。所以我目前使用以下代码来获得结果。

amount_a_and_b = len([None for _, elem2, elem3 in l if elem2 == 'a' or elem3 == 'b'])

但我得到了amount_a_and_b = 1,那么如何得到正确答案?

此外,是否有更优雅的方式(更少的代码或更高的性能或使用内置)来做到这一点?

5 个答案:

答案 0 :(得分:6)

我将列表展开为itertools.chain.from_iterable()并将其传递给collections.Counter() object

from collections import Counter
from itertools import chain

counts = Counter(chain.from_iterable(l))
amount_a_and_b = counts['a'] + counts['b']

或使用sum()计算值在展平序列中出现的次数:

from itertools import chain

amount_a_and_b = sum(1 for v in chain.from_iterable(l) if v in {'a', 'b'})

在我的Macbook Pro(OS X 10.11)上,这两种方法在Python 3.5.1上的速度非常可比:

>>> from timeit import timeit
>>> from collections import Counter
>>> from itertools import chain
>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')] * 1000  # make it interesting
>>> def counter():
...     counts = Counter(chain.from_iterable(l))
...     counts['a'] + counts['b']
...
>>> def summing():
...     sum(1 for v in chain.from_iterable(l) if v in {'a', 'b'})
...
>>> timeit(counter, number=1000)
0.5640139860006457
>>> timeit(summing, number=1000)
0.6066895100011607

答案 1 :(得分:1)

您希望避免将数据放入数据结构中。 [...]语法构造一个新列表并使用您放在...中的内容填充它,之后将获取数组的长度并且从不使用该数组。如果列表非常大,这会占用大量内存,而且通常不够优雅。您还可以使用迭代器循环遍历现有数据结构,例如:

sum(sum(c in ('a', 'b') for c in t) for t in l)

c in ('a', 'b')谓词是一个bool,在转换为int时计算结果为0或1,导致sum()仅在谓词计算为True时计算元组条目。

答案 2 :(得分:0)

只是为了好玩,使用reduce的功能方法:

>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]
>>> from functools import reduce
>>> reduce(lambda x, y: (1 if 'a' in y else 0) + (1 if 'b' in y else 0) + x, l, 0)
4

答案 3 :(得分:0)

您可以在一个列表解析中迭代列表和子列表:

len([i for sub_list in l for i in sub_list if i in ("a", "b")])

我认为这很简洁。

为避免创建临时列表,您可以使用生成器表达式创建1的序列并将其传递给sum

sum(1 for sub_list in l for i in sub_list if i in ("a", "b"))

答案 4 :(得分:0)

虽然这个问题已经有了一个公认的答案,但只是想知道为什么所有这些问题都如此复杂。我认为这就足够了。

>>> l = [(1, 'a', 'b'), (2, 'b', 'c'), (3, 'e', 'a')]
>>> total = sum(tup.count('a') + tup.count('b') for tup in l)
>>> total
4

或者

>>> total = sum(1 for tup in l for v in tup if v in {'a', 'b'})