2012-02-26 33 views
62

Powiel możliwe:
Efficient way to shift a list in pythonPython lista obrót

Chciałbym obracać listę Pythona przez dowolną liczbę pozycji w prawo lub w lewo (ten ostatni przy użyciu negatywna argument).

coś takiego:

>>> l = [1,2,3,4] 
>>> l.rotate(0) 
[1,2,3,4] 
>>> l.rotate(1) 
[4,1,2,3] 
>>> l.rotate(-1) 
[2,3,4,1] 
>>> l.rotate(4) 
[1,2,3,4] 

Jak można tego dokonać?

+2

Nie używam Python, ale jeśli masz metodę push/pop, możesz l.push (l.pop()). Następnie dla pętli. To obejmowałoby posuwanie się naprzód. –

+0

Czy [to pytanie] (http://stackoverflow.com/questions/2150108/efficient-way-to-shift-a-list-in-python) pomaga? – simchona

+0

To pytanie wydaje się być powiązane: http://stackoverflow.com/questions/1212025/moving-values-in-a-list-in-python –

Odpowiedz

118
def rotate(l, n): 
    return l[-n:] + l[:-n] 

dodatkowe wskazówki konwencjonalnego:

def rotate(l, n): 
    return l[n:] + l[:n] 

przykład:

example_list = [1, 2, 3, 4, 5] 

rotate(example_list, 2) 
# [3, 4, 5, 1, 2] 

Te argumenty rotate to lista i całkowitą oznaczająca zmianę. Funkcja tworzy dwie nowe listy przy użyciu slicing i zwraca konkatenację tych list. Funkcja rotate nie modyfikuje listy wejściowej.

+0

Ładne i proste. Obraca jednak kierunek przeciwny do podanego w pytaniu. –

+0

Uwielbiam elegancję! – varunl

+0

@DrewNakes więc to robi ... – YXD

82

W razie potrzeby można użyć collections.deque jako rozwiązanie:

import collections 

d = collections.deque([1,2,3,4,5]) 
d.rotate(3) 

print d 
>>> deque([3, 4, 5, 1, 2]) 

Jako bonus, będę oczekiwać, że będzie szybciej niż listy wbudowane.

+3

Dla przyszłych czytelników: 'collections.deque rotate()' jest szybszy niż krojenie według https://wiki.python.org/moin/TimeComplexity – Geoff

+0

czy nie należy wspomnieć, że domyślnie kolekcje obracają się w lewo? –

+0

@HasanIqbalAnik deque.rotate obraca się w prawo https://docs.python.org/3/library/collections.html#collections.deque.rotate – miles82

14

Poniższa funkcja będzie obracać listę l, x spacji aby prawej:

def rotate(l, x): 
    return l[-x:] + l[:-x] 

pamiętać, że będzie to tylko wrócić pierwotną listę jeśli x jest poza zakresem [-len(l), len(l)]. Aby pracować dla wszystkich wartości x, zastosowanie:

def rotate(li, x): 
    return li[-x % len(li):] + li[:-x % len(li)] 
+0

Czy jest na to sposób bez 'return'? Próbowałem 'l = l [n:] + l [: n]' ale kiedy próbuję zwrócić 'l', otrzymuję oryginał. – GinKin

+0

@GinKin Dlaczego bez zwrotu? W ten sposób zwracasz rzeczy z funkcji. To znaczy, możesz użyć lambda, ale to właśnie powoduje, że powrót jest niejawny. –

+0

Chcę, aby było "na miejscu", więc nic nie zwróci i jeśli napiszę '>>> l' po uruchomieniu funkcji, otrzymam obróconą listę, a nie oryginał. – GinKin

4
>>> l=[1,2,3,4] 
>>> l[1:]+l[:1] 
[2, 3, 4, 1] 
>>> l=[1,2,3,4] 
>>> l[2:]+l[:2] 
[3, 4, 1, 2] 
>>> l[-1:]+l[:-1] 
[4, 1, 2, 3] 

Ogólny obracać n w lewo (dodatni y w wywołaniu rotate) lub prawo (ujemny y), a następnie:

def rotate(l, y=1): 
    if len(l) == 0: 
     return l 
    y = y % len(l) # Why? this works for negative y 

    return l[y:] + l[:y] 

Jeśli chcesz, aby kierunek obrotu był taki sam jak Twój przykład, po prostu zaneguj y w obrocie.

def rotate(l, y=1): 
    if len(l) == 0: 
     return l 
    y = -y % len(l)  # flip rotation direction 

    return l[y:] + l[:y]