2012-01-21 13 views
17

Decir que tengo una lista,Pythonic Lista circular

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

Quiero agarrar el índice de un elemento arbitrario y los valores de sus vecinos. Por ejemplo,

i = l.index(n) 
j = l[i-1] 
k = l[i+1] 

Sin embargo, para el caso borde cuando i == len(l) - 1 esto falla. Así que pensé que acababa de lo envuelve alrededor,

if i == len(l) - 1: 
    k = l[0] 
else: 
    k = l[i+1] 

¿Hay una manera de hacer esto Pythonic?

+0

¿Desea un comportamiento especial, incluso si se proporciona un índice inferior a cero o superior a la longitud de la lista? – jimifiki

+0

Solo para envolver. Siempre quiero que 'j' y' k' señalen algo. Y quiero poder recorrer la lista completa a través de 'j' o' k'. – john

+0

aceptaste una respuesta sin ocuparte de los índices fuera de rango ... – jimifiki

Respuesta

32

Usted podría utilizar el módulo operador!

i = len(l) - 1 
jIndex = (i - 1) % len(l) 
kIndex = (i + 1) % len(l) 

j = l[jIndex] 
k = l[kIndex] 

O, para ser menos detallado:

k = l[(i + 1) % len(l)] 
+4

. Un comentario al azar: tenga en cuenta que si 0 <= i

6

La forma típica de adaptarse a los valores de un cierto rango es utilizar el operador %:

k = l[(i + 1) % len(l)] 
18

La forma más fácil para envolver alrededor de una lista de longitud fija es con el operador% (módulo)

list_element = my_list[idx % len(my_list)] 

pero de todos modos a ver http://docs.python.org/library/itertools.html

from itertools import cycle 

for p in cycle([1,2,3]): 
    print "endless cycle:", p 
+1

+1 para itertools.cycle – Eugen

0

En caso de que no quiera envolverse, la respuesta más pitonica sería usar rebanadas. Vecino desaparecido sustituido con Ninguno. Por ejemplo:

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

Es así como la función puede trabajar:

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

comporta de la siguiente

>>> env (a, 2,1) 
[13, 2, 3] 
>>> env (a,13,2) 
[7, 11, 13, 2, 3] 
>>> env (a,7,0) 
[7] 
1

Si lo desea, como clase, que fustigó a esta rápida CircularList:

class CircularList(list): 
    def __getitem__(self, x): 
     if isinstance(x, slice): 
      return [self[x] for x in self._rangeify(x)] 
     return super().__getitem__(x % len(self)) 

    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) 

Es compatible con el corte en lonchas, por lo

CircularList(range(10))[1:100] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8] 
0

Utilizando el método de módulo que otros han mencionado que he creado una clase con una propiedad que implementa una lista circular.

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 
Cuestiones relacionadas