【发布时间】:2010-11-27 01:59:05
【问题描述】:
假设我们有一个从 0 到 1000 的数字列表。是否有一种 pythonic/有效的方法来生成第一个和每个后续第 10 个项目的列表,即[0, 10, 20, 30, ... ]?
是的,我可以使用 for 循环来做到这一点,但我想知道是否有更简洁的方法来做到这一点,甚至可能在一行中?
【问题讨论】:
假设我们有一个从 0 到 1000 的数字列表。是否有一种 pythonic/有效的方法来生成第一个和每个后续第 10 个项目的列表,即[0, 10, 20, 30, ... ]?
是的,我可以使用 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]
请注意,这比循环和检查每个元素的模数快大约 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
【讨论】:
0 在l[0::10] 中是多余的。 l[::10] 更具可读性,更少混乱。
lst = list(range(1000)); lst1 = [lst[i] for i in range(0, len(lst), 10)]。在我的机器上,我得到“1000000 循环,最好的 5:每循环 395 纳秒”用于切片符号和“20000 循环,最好的 5:每循环 11.1 微秒”用于列表理解。
source_list[::10] 是最明显的,但这不适用于任何可迭代对象,并且对于大型列表而言内存效率不高。itertools.islice(source_sequence, 0, None, 10) 适用于任何可迭代对象且内存效率高,但可能不是大型列表和大步的最快解决方案。(source_list[i] for i in xrange(0, len(source_list), 10))【讨论】:
你可以像这样使用切片操作符:
l = [1,2,3,4,5]
l2 = l[::2] # get subsequent 2nd item
【讨论】:
L[2::2]
使用range(start, end, step)
li = list(range(0, 1000, 10))
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90 ... 990]
或者,如果您有一个列表,请使用 slice:来自手册:s[i:j:k] slice of s from i to j with step k
yourlist = [0, ... ,10 ...]
sub = yourlist[::10] # same as yourlist[0:100:10]
>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
【讨论】:
newlist = oldlist[::10]
这会挑选列表中的每 10 个元素。
【讨论】:
为什么不直接使用 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
【讨论】:
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]
【讨论】:
这是“每 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']
但这仍然比仅使用列表切片要慢得多。
【讨论】:
列表推导正是为此而生的:
smaller_list = [x for x in range(100001) if x % 10 == 0]
您可以在 python 官方文档中获得有关它们的更多信息: http://docs.python.org/tutorial/datastructures.html#list-comprehensions
【讨论】: