简体   繁体   English

返回较大列表中每个第 n 个项目的列表的 Pythonic 方法

[英]Pythonic way to return list of every nth item in a larger list

Say we have a list of numbers from 0 to 1000. Is there a pythonic/efficient way to produce a list of the first and every subsequent 10th item, ie [0, 10, 20, 30, ... ] ?假设我们有一个从 0 到 1000 的数字列表。是否有一种pythonic/有效的方法来生成第一个和每个后续第 10 个项目的列表,即[0, 10, 20, 30, ... ]

Yes, I can do this using a for loop, but I'm wondering if there is a neater way to do this, perhaps even in one line?是的,我可以使用 for 循环来做到这一点,但我想知道是否有一种更简洁的方法来做到这一点,甚至在一行中?

>>> lst = list(range(165))
>>> lst[0::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]

Note that this is around 100 times faster than looping and checking a modulus for each element:请注意,这比循环和检查每个元素的模数快约 100 倍:

$ python -m timeit -s "lst = list(range(1000))" "lst1 = [x for x in lst if x % 10 == 0]"
1000 loops, best of 3: 525 usec per loop
$ python -m timeit -s "lst = list(range(1000))" "lst1 = lst[0::10]"
100000 loops, best of 3: 4.02 usec per loop
  1. source_list[::10] is the most obvious, but this doesn't work for any iterable and is not memory efficient for large lists. source_list[::10]是最明显的,但这对任何可迭代对象都不起作用,并且对于大型列表来说内存效率不高。
  2. itertools.islice(source_sequence, 0, None, 10) works for any iterable and is memory-efficient, but probably is not the fastest solution for large list and big step. itertools.islice(source_sequence, 0, None, 10)适用于任何可迭代对象并且内存高效,但可能不是大列表和大步长的最快解决方案。
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

You can use the slice operator like this:您可以像这样使用切片运算符:

l = [1,2,3,4,5]
l2 = l[::2] # get subsequent 2nd item

From manual: s[i:j:k] slice of s from i to j with step k来自手册: s[i:j:k] slice of s from i to j with step k

li = range(100)
sub = li[0::10]

>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
newlist = oldlist[::10]

这将选出列表的每 10 个元素。

Why not just use a step parameter of range function as well to get:为什么不直接使用range函数的step参数来获得:

l = range(0, 1000, 10)

For comparison, on my machine:为了比较,在我的机器上:

H:\>python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
10000 loops, best of 3: 90.8 usec per loop
H:\>python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
1000000 loops, best of 3: 0.861 usec per loop
H:\>python -m timeit -s "l = range(0, 1000, 10)"
100000000 loops, best of 3: 0.0172 usec per loop
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]

Here is a better implementation of an "every 10th item" list comprehension, that does not use the list contents as part of the membership test:这是“每 10 个项目”列表理解的更好实现,它不使用列表内容作为成员资格测试的一部分:

>>> l = range(165)
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
>>> l = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
>>> [ item for i,item in enumerate(l) if i%10==0 ]
['A', 'K', 'U']

But this is still far slower than just using list slicing.但这仍然比仅使用列表切片要慢得多。

List comprehensions are exactly made for that:列表推导式正是为此而制作的:

smaller_list = [x for x in range(100001) if x % 10 == 0]

You can get more info about them in the python official documentation: http://docs.python.org/tutorial/datastructures.html#list-comprehensions你可以在 python 官方文档中获得更多关于它们的信息: http : //docs.python.org/tutorial/datastructures.html#list-comprehensions

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM