Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 以优雅的方式计算嵌套列表中的元素_Python_Python 3.x - Fatal编程技术网

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

Python 以优雅的方式计算嵌套列表中的元素,python,python-3.x,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']) 但是我得到了数量a和b=1,那么如何得到正确的答案呢 还有,有没有一种更优雅的方法可以减少代码或提高性能,或者使用内置程

我在列表中嵌套了元组,如

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'])
但是我得到了数量a和b=1,那么如何得到正确的答案呢

还有,有没有一种更优雅的方法可以减少代码或提高性能,或者使用内置程序来实现这一点?

我会将列表展平,并将其传递给:

或者使用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
我会将列表展平,并将其传递给:

或者使用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

只是为了好玩,使用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

只是为了好玩,使用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

您希望避免将数据放入数据结构中。[…]语法构造了一个新列表,并用您放入的内容填充它,之后,将获取数组的长度,并且永远不会使用该数组。如果列表非常大,则会占用大量内存,而且总体上不美观。您还可以使用迭代器在现有数据结构上循环,例如:

“a”中的sumc,“b”代表“t”中的c代表“l”中的t
“a”、“b”谓词中的c是一个布尔值,当转换为int时,它的计算结果为0或1,如果谓词的计算结果为True,则该和只计算元组项。

您希望避免将数据放入数据结构中。[…]语法构造了一个新列表,并用您放入的内容填充它,之后,将获取数组的长度,并且永远不会使用该数组。如果列表非常大,则会占用大量内存,而且总体上不美观。您还可以使用迭代器在现有数据结构上循环,例如:

“a”中的sumc,“b”代表“t”中的c代表“l”中的t
“a”、“b”谓词中的c是一个布尔值,当转换为int时,它的计算结果为0或1,如果谓词的计算结果为True,则该和仅计算元组项。

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

len([i for sub_list in l for i in sub_list if i in ("a", "b")])
我认为这相当简洁

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


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

len([i for sub_list in l for i in sub_list if i in ("a", "b")])
我认为这相当简洁

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


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

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


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

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



这实际上是你程序中的一个瓶颈吗?@MartijnPieters抱歉,我已经更新了我的答案。我回滚了你上次的编辑,因为这完全改变了你问题的性质,这对所有回答你问题的前一版本的人都不公平。如果t中的“-”不在t中,则l中t的sum1将实现您的另一个版本。@MartijnPieters没关系。这是最好的选择。这实际上是你程序中的一个瓶颈吗?@MartijnPieters抱歉,我已经更新了我的答案。我回滚了你上次的编辑,因为这完全改变了你问题的性质,这对所有回答你问题的人都不公平。如果t中的“-”不在t中,则l中t的sum1将实现您的另一个版本。@MartijnPieters没关系。这是最好的选择。我根本无法重现这些时间。reduced在0.7757142429982196时慢了约25%。@MartijnPieters,刚刚再次运行,结果仍然几乎相同…可能是处理器的东西?我试试我的笔记本电脑什么版本的Python?我在OSXMacBookPro上使用的是3.5.1,这些数字毫无意义。lambda为l中的每个元组执行大量字节码。对于求和方法,这不可能比每次迭代进行单集成员资格测试更快。@MartijnPieters,刚刚在W10上的3.5.1上进行了尝试,是的,从0.77到0.85左右。我根本无法重现这些计时。reduced在0.7757142429982196时慢了约25%。@MartijnPieters,刚刚再次运行,结果仍然几乎相同…可能是处理器的东西?我试试我的笔记本电脑什么版本的Python?我在OSXMacBookPro上使用的是3.5.1,这些数字毫无意义。lambda为l中的每个元组执行大量字节码。对于求和方法,这不可能比每次迭代进行单集成员资格测试更快。@MartijnPieters,刚刚在W10上的3.5.1上进行了尝试,正确,从0.77到0.85左右。这比相同时间的测试慢3倍多:1.9530742168426514单击:cast不是正确的术语;bool只是
int和True与False已经是整数了。不需要强制转换,它们加起来只有一个整数值。这确实比求和慢,因为链迭代器可能是本机实现的,这使得它比纯Python中的嵌套循环更有效。然而,在我的机器上,它比计数器方法快。我确实喜欢可读性,而且它不使用辅助函数,所以对于小数组,我会使用它。我同意链式迭代器更适合于数组可能较大的情况。您是否在Python2上进行测试?计数器在Python3中得到了一个C优化。这比相同时间的测试慢了3倍多:1.9530742168426514单击:cast不是正确的术语;bool只是int的一个子类,因此True和False已经是整数了。不需要强制转换,它们加起来只有一个整数值。这确实比求和慢,因为链迭代器可能是本机实现的,这使得它比纯Python中的嵌套循环更有效。然而,在我的机器上,它比计数器方法快。我确实喜欢可读性,而且它不使用辅助函数,所以对于小数组,我会使用它。我同意链式迭代器更适合于数组可能较大的情况。您是否在Python2上进行测试?计数器在Python3中得到了C优化。在外部创建集合是faster@PadraicCunningham:在Python 2或3中?我只能在结束时稍微慢一点。考虑到{…}中的窥视孔是优化的,集合作为冻结集存储在代码对象常量中,每次迭代都使用一个加载常量操作码来加载它。使用3.5.2st={a,b}然后对链中的v使用sum1。如果v in st,则从_iterablel对链中的v使用sum1。如果v in{a',b},则从_iterablel2.12毫秒vs 2。54ms@PadraicCunningham:在函数中?st是一个闭包,不能转化为常数。LOAD_DEREF比LOAD_CONST要做更多的工作,所以我觉得这有点难以置信。另外,我确实试过了,但无法再现你似乎已经发现的速度提升。在室外创建场景是非常困难的faster@PadraicCunningham:在Python 2或3中?我只能在结束时稍微慢一点。考虑到{…}中的窥视孔是优化的,集合作为冻结集存储在代码对象常量中,每次迭代都使用一个加载常量操作码来加载它。使用3.5.2st={a,b}然后对链中的v使用sum1。如果v in st,则从_iterablel对链中的v使用sum1。如果v in{a',b},则从_iterablel2.12毫秒vs 2。54ms@PadraicCunningham:在函数中?st是一个闭包,不能转化为常数。LOAD_DEREF比LOAD_CONST要做更多的工作,所以我觉得这有点难以置信。另外,我确实尝试过,但无法重现您似乎已经发现的速度提升。在C代码中,使用tuple.count对每个tuple进行完整遍历。你现在这样做两次;itertools.chain.from_iterable只需要迭代每个元组一次。因此,这种方法需要0.9097697560064262,比传统方法多60%的时间;字节码必须在与chain.from_iterable相同的步数上迭代,因此最终得到'0.5921581570000853'。在C代码中,使用tuple.count对每个元组进行完整遍历。你现在这样做两次;itertools.chain.from_iterable只需要迭代每个元组一次。因此,这种方法需要0.9097697560064262,比传统方法多60%的时间;字节码必须迭代与chain.from_iterable相同的步骤数,因此最终得到'0.5921581570000853.in。。在这种情况下,元组测试比较慢,但主要是因为小字符串“a”和“b”可以被插入,所以在测试集合成员资格时使用身份测试,这只是指针比较。但是,我从一开始就使用sum,因为,正如您所注意到的,创建一个列表对象只是为了获取长度是一种内存浪费,内存分配也需要时间!在。。在这种情况下,元组测试比较慢,但主要是因为小字符串“a”和“b”可以被插入,所以在测试集合成员资格时使用身份测试,这只是指针比较。但是,我从一开始就使用sum,因为,正如您所注意到的,创建一个列表对象只是为了获取长度是一种内存浪费,内存分配也需要时间!