Use slice notation with collections.deque

前端 未结 6 2002
情话喂你
情话喂你 2020-12-05 06:00

How would you extract items 3..6 efficiently, elegantly and pythonically from the following deque without altering it:

from collections import d         


        
相关标签:
6条回答
  • 2020-12-05 06:41

    I would prefer this, it's shorter so easier to read:

    output = list(q)[3:6+1]
    
    0 讨论(0)
  • 2020-12-05 06:41
    output = [q[i] for i in range(3,6+1)]
    
    0 讨论(0)
  • 2020-12-05 06:58
    import itertools
    output = list(itertools.islice(q, 3, 7))
    

    For example:

    >>> 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]
    

    This should be more efficient the the other solutions posted so far. Proof?

    [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
    
    0 讨论(0)
  • 2020-12-05 06:58

    I'd add this as a new answer, to provide better formatting.

    For simplicity, Shawn's answer is perfect, but if you often need to get a slice from dequeue, you might prefer to subclass it and add a __getslice__ method.

    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))
    

    This won't support setting a new slice, but you can implement your own custom __setslice__ method using the same concept.

    NOTE: this is valid for Python <=2.* only. It's also worth noticing that, while __getslice__ is deprecated since python 2.0, the documentation still reports this for the latest 2.7 release:

    (However, built-in types in CPython currently still implement __getslice__(). Therefore, you have to override it in derived classes when implementing slicing.)

    0 讨论(0)
  • 2020-12-05 06:59

    you can override the __getitem__ method and create a SliceableDeque using islice.

    There are edge cases, you should consider (for example using negative slices doesn't work with islice).

    here is what I have been using:

    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))
    
    0 讨论(0)
  • 2020-12-05 06:59

    This is an old question, but for any future travelers, the Python docs explicitly recommend using rotate for this:

    The rotate() method provides a way to implement deque slicing and deletion.

    https://docs.python.org/2/library/collections.html

    An implementation is relatively simple:

    def slice_deque(d, start, stop, step):
        d.rotate(-start)
        slice = list(itertools.islice(d, 0, stop-start, step))
        d.rotate(start)
        return slice
    

    Effectively the same as using islice directly, except that rotate is more efficient for skipping through to the starting point. On the other hand, it also temporarily modifies the deque, which could be a threadsafety concern.

    0 讨论(0)
提交回复
热议问题