2012-01-21 14 views
17

Powiedzmy mam listę,pythonowy Circular Lista

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

chcę chwycić indeks dowolnego elementu i wartości swoich sąsiadów. Na przykład,

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

Jednakże w przypadku, gdy krawędź i == len(l) - 1 to się nie powiedzie. Tak więc pomyślałem, że po prostu owijałem,

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

Czy jest to pythonic sposób to zrobić?

+0

Czy chcesz zachować specjalne zachowanie, nawet jeśli indeks jest mniejszy niż zero lub większy niż długość listy? – jimifiki

+0

Tylko do zawijania. Zawsze chcę, żeby 'j' i' k' wskazywały na coś. I chcę móc przechodzić całą listę przez 'j' lub' k'. – john

+0

zaakceptowałeś odpowiedź, nie dbając o indeksy poza zasięgiem ... – jimifiki

Odpowiedz

32

Można użyć operatora modulo!

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

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

Albo, być mniej gadatliwy:

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

Losowy komentarz: zauważ, że jeśli 0 <= i

6

Typowym sposobem, aby dopasować wartości w pewnym zakresie jest użycie operatora %:

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

Najłatwiej owinąć wokół listę stała długość jest z (modulo) operatora%

list_element = my_list[idx % len(my_list)] 

ale mimo to patrzeć http://docs.python.org/library/itertools.html

from itertools import cycle 

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

+1 dla itertools.cycle – Eugen

0

Jeśli nie chcesz się owijać, najczęstszą odpowiedzią Pythonona będzie użycie plasterków. Brakujący sąsiad zastępuje Brak. Np:

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

ten sposób funkcja może działać:

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

zachowuje się następująco

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

Jeśli chcesz go jako klasa I bita to szybkie 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) 

Obsługuje krojenie, więc

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

Stosując metodę modulo że wspominają inni Stworzyłem klasę z nieruchomości, która implementuje listę kołową.

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