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


170

假设我们有一个从0到1000的数字列表。是否有一种pythonic /高效的方法来生成第一个以及随后的第10个项目的列表,即[0, 10, 20, 30, ... ]

是的,我可以使用for循环来执行此操作,但是我想知道是否有更整洁的方法可以执行此操作,甚至在一行中也可以?

Answers:


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

请注意,这比循环并检查每个元素的模量快约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

4
当然,列表理解通常更强大。OTOH,该问题提出了一个现有列表,在这种情况下,切片可以正常工作。
内德·迪利

我在列表理解答案中对此进行了评论。请注意“如果x%10 == 0”。它仅适用于此特定列表示例,但是如果输入列表例如为l = range(0,1000,2),它将不会每隔第10个项目退出一次。
安德烈·米勒

12
@安德烈:非常正确。因此,这是切片语言运算符这一卑鄙的语言功能的示例,在这种情况下,结果(1)使它更容易获得正确的结果;(2)表达更简洁;(3)快2个数量级。(1)当然是迄今为止最重要的问题,但是,由于该语言的精心设计和实现,您可以以1的价格获得全部这三种语言。好的问题和答案。
内德·迪利2009年

2
在中0是多余的l[0::10]l[::10]更具可读性,减少混乱。
康斯坦丁·舒伯特

我对性能比较感到惊讶,列表理解为0.5秒,列表切片为0.4秒。似乎很慢,为什么列表切片需要10万个循环才能生成大小为1000的列表!
达莫

57
  1. source_list[::10] 是最明显的,但这对任何可迭代的方法都无效,并且对于大列表而言内存效率不高。
  2. itertools.islice(source_sequence, 0, None, 10) 适用于任何可迭代且内存有效的方法,但对于大型列表和大型步骤而言,可能不是最快的解决方案。
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

1
+1最佳答案,IMO。所有这三个建议都是一个通用解决方案(即,将源清单作为给定的)。生成器解决方案(3.)很不错,因为它根据源列表的索引进行过滤。它的内存效率可能高达2。索引和结果列表都是生成器,因此构造得很慢,如果您不需要单个块中的结果列表,那么这可能也是最快的。只有当源列表可以是一个生成器时,我才会使用Paul的“ item,i in enumerate(l)”这个成语,因为没有len()生成器。顺便说一句,哪种迭代方法不适用于1.?发电机?!
ThomasH

Iterable =使用__iter __()方法返回迭代器的对象(使用next()方法的对象)
Denis Otkidach 09年


19

从手册: 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]

13
newlist = oldlist[::10]

这将选择列表中的第10个元素。


4

为什么不只使用range函数的step参数来获得:

l = range(0, 1000, 10)

为了进行比较,在我的机器上:

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

3
@SilentGhost:的确如此,但是由于这是一个初学者的问题,范围函数可能是他们真正想做的,所以我认为这是一个有效的答案。(尽管上限应该是1001,而不是1000)
Scott Griffiths

2
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]

1
当range(0,1001,10)已经只占用第10个元素时,为什么会有if子句?
Autoplectic

4
在此处发表评论,这不能解决“以Python的方式返回较大列表中第n个项目的列表的更一般的问题”的解决方案,您的解决方案取决于示例列表的值为0到1000,并且仅提取项目列表中的值被10整除而不是第10个项目。
安德烈·米勒

1
好吧,OP写道:“我们有一个从零到1000的数字列表”。因此,他不需要通用的解决方案。

1
他写了“说我们有..”,这只是一个例子。如果他真的想要从零到1000的列表中的每10个数字,那么答案将是range(0,1001,10)或类似的值。
安德烈·米勒

1

这是“每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']

但这仍然比仅使用列表切片要慢得多。


-9

列表理解正是为此而做出的:

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

您可以在python官方文档中获取有关它们的更多信息:http : //docs.python.org/tutorial/datastructures.html#list-comprehensions


上限应为1000,而不是10000。您的解决方案不包括上限1000,因为范围停在999。列表理解的链接为+1。

19
实际上,这并不是每10个项目抽取一次,而是将值除以10的每个项目抽取出来。在此特定示例中,它是相同的东西,但可能并非如此。
安德烈·米勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.