python – 来自右侧的islice

对于列表,可以使用切片my_list [-10:]来获取最后(最多)10个元素

我想用itertools.islice做同样的事情.在这种情况下,我有一个collections.deque.

有没有比以下更有效的方法呢?

from collections import deque
import itertools
my_deque = deque()
my_list = list()
for i in range(100):
    my_deque.append(i)
    my_list.append(i)

然后我们做切片:

start = max(0, len(my_deque) - 10)
for i in list(itertools.islice(my_deque, start, None)):
    pass

我的时间:

deque:1000000个循环,最好是每个循环3:962 ns

list slicing:10000000个循环,最佳3:95.9 ns每个循环

最佳答案 当你发现没有办法切割collections.deque.但它支持在这种情况下可以使用的旋转:

last_n = 10
my_deque.rotate(last_n)
for i in itertools.islice(my_deque, last_n):
    pass

在这种情况下,itertools.islice的问题是它需要迭代所有元素,直到它到达停止.这是因为它通常不仅需要使用像列表和deques这样的随机访问容器来使用迭代器.所以在你的情况下,islice真的必须遍历deque中的所有元素.使用旋转然后islice它只需迭代10个元素.

至于时间,很难知道你比较了什么,但使用这个设置:

from collections import deque
import itertools
my_deque = deque(range(10000))
my_list = list(range(10000))

我得到以下时间:

%%timeit

my_deque.rotate(10)
for i in itertools.islice(my_deque, 10):
    pass
my_deque.rotate(-10)  # so the next timing operates on the orginal deque again

2.76 µs ± 41.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit

start = max(0, len(my_deque) - 10)
for i in itertools.islice(my_deque, start, None):
    pass

136 µs ± 8.08 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit

start = max(0, len(my_list) - 10)
for i in itertools.islice(my_list, start, None):
    pass

119 µs ± 1.64 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit my_list[-10:]

434 ns ± 12.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

所以它不能击败列表切片(仍然慢〜5倍),但它肯定比使用你的islice方法快得多(~50倍).

点赞