您将如何在deque
不更改以下内容的情况下有效、优雅和 Python 地提取项目 3..6:
from collections import deque
q = deque('',maxlen=10)
for i in range(10,20):
q.append(i)
切片符号似乎不适用于deque
...
import itertools
output = list(itertools.islice(q, 3, 7))
例如:
>>> import collections, itertools
>>> q = collections.deque(xrange(10, 20))
>>> q
deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> list(itertools.islice(q, 3, 7))
[13, 14, 15, 16]
这应该比迄今为止发布的其他解决方案更有效。证明?
[me@home]$ SETUP="import itertools,collections; q=collections.deque(xrange(1000000))"
[me@home]$ python -m timeit "$SETUP" "list(itertools.islice(q, 10000, 20000))"
10 loops, best of 3: 68 msec per loop
[me@home]$ python -m timeit "$SETUP" "[q[i] for i in xrange(10000, 20000)]"
10 loops, best of 3: 98.4 msec per loop
[me@home]$ python -m timeit "$SETUP" "list(q)[10000:20000]"
10 loops, best of 3: 107 msec per loop
我更喜欢这个,它更短更容易阅读:
output = list(q)[3:6+1]
我会将其添加为新答案,以提供更好的格式。
为简单起见,Shawn 的答案是完美的,但如果您经常需要从中获取切片dequeue
,您可能更愿意对其进行子类化并添加一个__getslice__
方法。
from collections import deque
from itertools import islice
class deque_slice(deque):
def __new__(cls, *args):
return deque.__new__(cls, *args)
def __getslice__(self, start, end):
return list(islice(self, start, end))
这不支持设置新切片,但您可以使用相同的概念实现自己的自定义__setslice__
方法。
注意:这仅对 Python <=2.* 有效。还值得注意的是,虽然自 python 2.0 以来__getslice__
已弃用,但文档仍然报告了最新的 2.7 版本:
(但是,目前 CPython 中的内置类型仍然实现
__getslice__()
. 因此,在实现切片时,您必须在派生类中覆盖它。)
这是一个老问题,但对于任何未来的旅行者,Python 文档明确建议使用rotate
:
rotate() 方法提供了一种实现双端队列切片和删除的方法。
https://docs.python.org/2/library/collections.html
一个实现相对简单:
def slice_deque(d, start, stop, step):
d.rotate(-start)
slice = list(itertools.islice(d, 0, stop-start, step))
d.rotate(start)
return slice
islice
效果与直接使用相同,只是rotate
跳到起点更有效。另一方面,它也会临时修改双端队列,这可能是线程安全问题。
output = [q[i] for i in range(3,6+1)]
您可以覆盖该 __getitem__
方法并创建一个SliceableDeque
using islice
。
有一些边缘情况,您应该考虑(例如,使用负切片不适用于islice
)。
这是我一直在使用的:
import itertools
from collections import deque
class SliceableDeque(deque):
def __getitem__(self, s):
try:
start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1
except AttributeError: # not a slice but an int
return super().__getitem__(s)
try: # normal slicing
return list(itertools.islice(self, start, stop, step))
except ValueError: # incase of a negative slice object
length = len(self)
start, stop = length + start if start < 0 else start, length + stop if stop < 0 else stop
return list(itertools.islice(self, start, stop, step))