次のdeque
からアイテム3..6を効率的に、エレガントに、Pythonで、変更せずにどのように抽出しますか。
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]
output = [q[i] for i in range(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))
これはsetting新しいスライスをサポートしませんが、同じ概念を使用して独自のカスタム__setslice__
メソッドを実装できます。
これは古い質問ですが、今後の旅行者のために、Python docsは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
が開始点までスキップするのに効率的です。一方、それはまた、一時的に両端キューを変更しますが、これはスレッドセーフの問題となる可能性があります。
__getitem__
メソッドを使用し、SliceableDeque
を使用してislice
を作成します。
Edgeのケースがあります。検討する必要があります(たとえば、負のスライスの使用は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)
else:
try:
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))