Pythonic Circular List

前端 未结 7 1893
闹比i
闹比i 2020-12-03 01:10

Say I have a list,

l = [1, 2, 3, 4, 5, 6, 7, 8]

I want to grab the index of an arbitrary element and the values of its neighbors. For examp

相关标签:
7条回答
  • 2020-12-03 01:44
    a = [2,3,5,7,11,13]
    
    def env (l, n, count):
        from itertools import cycle, islice
        index = l.index(n) + len(l)
        aux = islice (cycle (l), index - count, index + count + 1)
        return list(aux)
    

    Behaves as follows

    >>> env (a, 2,1)
    [13, 2, 3]
    >>> env (a,13,2)
    [7, 11, 13, 2, 3]
    >>> env (a,7,0)
    [7]
    
    0 讨论(0)
  • 2020-12-03 01:46

    In case you do not want to wrap around, the most Pythonic answer would be to use slices. Missing neighbor substituted with None. E.g.:

    def nbrs(l, e):
       i = l.index(e)
       return (l[i-1:i] + [None])[0], (l[i+1:i+2] + [None])[0]
    

    This is how the function can work:

    >>> nbrs([2,3,4,1], 1)
    (4, None)
    >>> nbrs([1,2,3], 1)
    (None, 2)
    >>> nbrs([2,3,4,1,5,6], 1)
    (4, 5)
    >>> nbrs([], 1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in nbrs
    ValueError: 1 is not in list
    
    0 讨论(0)
  • 2020-12-03 01:49

    The easiest way to wrap around a fixed length list is with the % (modulo) operator

    list_element = my_list[idx % len(my_list)]
    

    but anyway look at http://docs.python.org/library/itertools.html

    from itertools import cycle
    
    for p in cycle([1,2,3]):
      print "endless cycle:", p
    
    0 讨论(0)
  • 2020-12-03 01:53

    Using the modulo method that others have mentioned I have created a class with a property that implements a circular list.

    class Circle:
        """Creates a circular array of numbers
    
        >>> c = Circle(30)
        >>> c.position
        -1
        >>> c.position = 10
        >>> c.position
        10
        >>> c.position = 20
        >>> c.position
        20
        >>> c.position = 30
        >>> c.position
        0
        >>> c.position = -5
        >>> c.position
        25
        >>>
    
        """
        def __init__(self, size):
            if not isinstance(size, int):  # validating length
                raise TypeError("Only integers are allowed")
            self.size = size
    
        @property
        def position(self):
            try:
                return self._position
            except AttributeError:
                return -1
    
        @position.setter
        def position(self, value):
            positions = [x for x in range(0, self.size)]
            i = len(positions) - 1
            k = positions[(i + value + 1) % len(positions)]
            self._position = k
    
    0 讨论(0)
  • 2020-12-03 01:55

    The typical way to fit values to a certain range is to use the % operator:

    k = l[(i + 1) % len(l)]
    
    0 讨论(0)
  • 2020-12-03 01:56

    If you want it as a class, I whipped up this quick CircularList:

    import operator
    
    class CircularList(list):
        def __getitem__(self, x):
            if isinstance(x, slice):
                return [self[x] for x in self._rangeify(x)]
    
            index = operator.index(x)
            try:
                return super().__getitem__(index % len(self))
            except ZeroDivisionError:
                raise IndexError('list index out of range')
    
        def _rangeify(self, slice):
            start, stop, step = slice.start, slice.stop, slice.step
            if start is None:
                start = 0
            if stop is None:
                stop = len(self)
            if step is None:
                step = 1
            return range(start, stop, step)
    

    It supports slicing, so

    CircularList(range(5))[1:10] == [1, 2, 3, 4, 0, 1, 2, 3, 4]
    
    0 讨论(0)
提交回复
热议问题