Modo efficiente per ruotare un elenco in Python


263

Qual è il modo più efficiente per ruotare un elenco in Python? In questo momento ho qualcosa del genere:

>>> def rotate(l, n):
...     return l[n:] + l[:n]
... 
>>> l = [1,2,3,4]
>>> rotate(l,1)
[2, 3, 4, 1]
>>> rotate(l,2)
[3, 4, 1, 2]
>>> rotate(l,0)
[1, 2, 3, 4]
>>> rotate(l,-1)
[4, 1, 2, 3]

C'è un modo migliore?


12
Questo non è realmente mutevole poiché le altre lingue (Perl, Ruby) usano il termine. Questo è ruotare. Forse la domanda dovrebbe essere aggiornata di conseguenza?
Vincent Fourmond,

@dzhelil Mi piace molto la tua soluzione originale perché non introduce mutazioni
juanchito


2
Penso che rotatesia la parola giusta, no shift.
codeforester

2
La vera risposta corretta è che non dovresti mai ruotare l'elenco in primo luogo. Crea una variabile "puntatore" nel punto logico del tuo elenco dove desideri che sia la "testa" o la "coda" e modifica quella variabile invece di spostare uno degli elementi nell'elenco. Cerca l'operatore "modulo"% per il modo efficiente di "avvolgere" il puntatore all'inizio e alla fine dell'elenco.
CND

Risposte:


280

A collections.dequeè ottimizzato per tirare e spingere su entrambe le estremità. Hanno anche un rotate()metodo dedicato .

from collections import deque
items = deque([1, 2])
items.append(3)        # deque == [1, 2, 3]
items.rotate(1)        # The deque is now: [3, 1, 2]
items.rotate(-1)       # Returns deque to original state: [1, 2, 3]
item = items.popleft() # deque == [2, 3]

8
Per i lettori futuri: collections.deque rotate()è più veloce dell'affettare
Geoff

2
Ma attenzione, l'utilizzo deque.rotaterichiede prima una conversione del tipo in un dequeoggetto, che è più lento di l.append(l.pop(0)). Quindi, se hai un oggetto deque con cui iniziare, assicurati che sia il più veloce. Altrimenti, usa l.append(l.pop(0)).
Purrell,

8
Per elaborare, deque.rotateè O (k) ma digitare la conversione da lista a deque è O (n) . Quindi, se inizi con un elenco, usare deque.rotate è O (n) + O (k) = O (n). l.append(l.pop(0))d'altra parte è O (1).
Purrell,

3
@Purrell, facendo scattare l'elemento frontale è O (n). In wiki.python.org/moin/TimeComplexity è elencato come O (k) e k è il numero di elementi nell'elenco che segue l'elemento spuntato, perché la struttura dei dati sposta tutti gli elementi seguenti verso la parte anteriore dell'elenco. Per questo motivo, solo l'ultimo elemento può essere visualizzato in O (1) tempo.
Kirk Boyer,

88

Che ne dici di usare solo pop(0)?

list.pop([i])

Rimuovere l'elemento nella posizione specificata nell'elenco e restituirlo. Se non viene specificato alcun indice, a.pop()rimuove e restituisce l'ultimo elemento nell'elenco. (Le parentesi quadre intorno alla ifirma del metodo indicano che il parametro è facoltativo, non che dovresti digitare parentesi quadre in quella posizione. Vedrai questa notazione frequentemente nel Python Library Reference.)


16
Ma non costerebbe O (k) per rimuovere ogni elemento nell'elenco dove k è il numero di elementi rimanenti. Quindi il tempo totale sarà O (n ^ 2) wiki.python.org/moin/TimeComplexity
Pramod

5
Questo non risponde davvero alla domanda. La domanda non riguarda la restituzione degli articoli in ordine, ma piuttosto la creazione di un nuovo elenco in un ordine diverso.
user650261

5
no, la risposta alla domanda usando pop sarebbe l.append(l.pop(0). Che se non sbaglio è O (1).
Purrell,

4
list.pop chiama internamente list_ass_slice che utilizza memmove per spostare molto rapidamente tutti gli elementi, ma è comunque O (n). Vedi github.com/python/cpython/blob/master/Objects/listobject.c e wiki.python.org/moin/TimeComplexity . L'unico elemento che può essere rimosso da un elenco Python a tempo costante è l'ultimo.
DRayX,

2
Downvoted. Da docs.python.org/3/tutorial/… È anche possibile utilizzare un elenco come una coda, in cui il primo elemento aggiunto è il primo elemento recuperato (“first-in, first-out”); tuttavia, gli elenchi non sono efficienti per questo scopo. Mentre gli appendi e i pop dalla fine dell'elenco sono veloci, fare inserimenti o pop dall'inizio di un elenco è lento (perché tutti gli altri elementi devono essere spostati di uno).
SantaXL

59

Numpy può farlo usando il rollcomando:

>>> import numpy
>>> a=numpy.arange(1,10) #Generate some data
>>> numpy.roll(a,1)
array([9, 1, 2, 3, 4, 5, 6, 7, 8])
>>> numpy.roll(a,-1)
array([2, 3, 4, 5, 6, 7, 8, 9, 1])
>>> numpy.roll(a,5)
array([5, 6, 7, 8, 9, 1, 2, 3, 4])
>>> numpy.roll(a,9)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

1
Quello che amo di SO è che a volte nei feed delle risposte puoi trovare alcuni nuovi fantastici tesori come questo :)
noamgot

Questo, quando l'ho provato, è molto, molto lento
Peter Harrison,

@PeterHarrison: Dal momento che non fornisci i dettagli del test, è difficile sapere cosa intendi. Questa risposta fornisce i dettagli completi dei test e un confronto temporale.
Richard,

33

Dipende da cosa vuoi che accada quando fai questo:

>>> shift([1,2,3], 14)

Potresti voler cambiare il tuo:

def shift(seq, n):
    return seq[n:]+seq[:n]

per:

def shift(seq, n):
    n = n % len(seq)
    return seq[n:] + seq[:n]

5
NB: Questo si arresterà in modo anomalo per elenchi vuoti.
meawoppl

n = n% len (seq) return = seq [-n:] + seq [: - n]
user3303020

Puoi spiegare perché n = n% len (seq)?
AerysS

16

Il modo più semplice che mi viene in mente:

a.append(a.pop(0))

3
Questo è il modo più veloce per gli elenchi. collections.dequeè più veloce, ma per i casi più comuni di lunghezza dell'elenco su una singola iterazione o qualsiasi caso di più iterazioni, a.append(a.pop(0))sarà più veloce della conversione del tipo in deque
Purrell

@runDOS Esegui la risposta perfetta a questa domanda che è purtroppo chiusa come duplicato. Forse voterai per riaprirlo?
Lupo,

15

Se vuoi solo iterare su questi insiemi di elementi piuttosto che costruire una struttura di dati separata, considera l'utilizzo di iteratori per costruire un'espressione del generatore:

def shift(l,n):
    return itertools.islice(itertools.cycle(l),n,n+len(l))

>>> list(shift([1,2,3],1))
[2, 3, 1]

11

Ciò dipende anche se si desidera spostare l'elenco in posizione (mutandolo) o se si desidera che la funzione restituisca un nuovo elenco. Perché, secondo i miei test, qualcosa del genere è almeno venti volte più veloce della tua implementazione che aggiunge due elenchi:

def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l

In effetti, anche aggiungendo a l = l[:] in cima a quello per operare su una copia dell'elenco trasmesso è ancora due volte più veloce.

Varie implementazioni con alcuni tempi su http://gist.github.com/288272


3
Invece di l[:n] = []andare per del l[:n]. Solo un'alternativa.
martedì

1
Oh, sì, buon vecchio del. Mi dimentico spesso di del; l'operazione dell'elenco è un'istruzione, non un metodo. Py3k ha cambiato quella stranezza o ce l'abbiamo ancora?
keturn,

2
@keturn: delè ancora una dichiarazione in Py3. Tuttavia x.__delitem__(y) <==> del x[y], quindi se preferisci usare i metodi, l.__delitem__(slice(n))è anche equivalente e funziona sia in 2 che in 3.
martineau

9

Solo alcune note sui tempi:

Se stai iniziando con un elenco, l.append(l.pop(0))è il metodo più veloce che puoi utilizzare. Questo può essere mostrato con la sola complessità temporale:

  • deque.rotate è O (k) (k = numero di elementi)
  • la conversione da lista a deque è O (n)
  • list.append e list.pop sono entrambi O (1)

Quindi, se stai iniziando con dequeoggetti, puoi deque.rotate()al costo di O (k). Ma, se il punto di partenza è un elenco, la complessità temporale dell'uso deque.rotate()è O (n). l.append(l.pop(0)è più veloce in O (1).

Solo a scopo illustrativo, ecco alcuni esempi di temporizzazioni su iterazioni 1M:

Metodi che richiedono la conversione del tipo:

  • deque.rotatecon oggetto deque: 0,12380790710449219 secondi (il più veloce)
  • deque.rotatecon conversione del tipo: 6,853878974914551 secondi
  • np.rollcon nparray: 6.0491721630096436 secondi
  • np.rollcon conversione del tipo: 27.558452129364014 secondi

Elenco dei metodi menzionati qui:

  • l.append(l.pop(0)): 0,32483696937561035 secondi (il più veloce)
  • "shiftInPlace ": 4.819645881652832 secondi
  • ...

Il codice temporale utilizzato è di seguito.


collections.deque

Mostrando che la creazione di deques dagli elenchi è O (n):

from collections import deque
import big_o

def create_deque_from_list(l):
     return deque(l)

best, others = big_o.big_o(create_deque_from_list, lambda n: big_o.datagen.integers(n, -100, 100))
print best

# --> Linear: time = -2.6E-05 + 1.8E-08*n

Se è necessario creare oggetti deque:

1M iterazioni @ 6,853878974914551 secondi

setup_deque_rotate_with_create_deque = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
"""

test_deque_rotate_with_create_deque = """
dl = deque(l)
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_with_create_deque, setup_deque_rotate_with_create_deque)

Se hai già oggetti deque:

Iterazioni 1M a 0,12380790710449219 secondi

setup_deque_rotate_alone = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
dl = deque(l)
"""

test_deque_rotate_alone= """
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_alone, setup_deque_rotate_alone)

np.roll

Se è necessario creare nparray

1M iterazioni @ 27.558452129364014 secondi

setup_np_roll_with_create_npa = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
"""

test_np_roll_with_create_npa = """
np.roll(l,-1) # implicit conversion of l to np.nparray
"""

Se hai già nparray:

1M iterazioni @ 6.0491721630096436 secondi

setup_np_roll_alone = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
npa = np.array(l)
"""

test_roll_alone = """
np.roll(npa,-1)
"""
timeit.timeit(test_roll_alone, setup_np_roll_alone)

"Spostamento sul posto"

Non richiede conversione di tipo

Iterazioni 1M @ 4.819645881652832 secondi

setup_shift_in_place="""
import random
l = [random.random() for i in range(1000)]
def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l
"""

test_shift_in_place="""
shiftInPlace(l,-1)
"""

timeit.timeit(test_shift_in_place, setup_shift_in_place)

l.append (l.pop (0))

Non richiede conversione di tipo

1M iterazioni @ 0.32483696937561035

setup_append_pop="""
import random
l = [random.random() for i in range(1000)]
"""

test_append_pop="""
l.append(l.pop(0))
"""
timeit.timeit(test_append_pop, setup_append_pop)

2
mentre list.pop () è un'operazione a tempo costante, list.pop (0) non lo è . Funziona in tempo lineare rispetto alla lunghezza della lista. Puoi verificarlo modificando la tua impostazione timeit:l = [random.random() for i in range(100000)]
emu

1
list.pop non è un'operazione a tempo costante. list.pop viene eseguito nel tempo O (k) in cui k è il numero di elementi oltre l'elemento rimosso, quindi list.pop (0) è O (n). Internamente, list.pop usa list_ass_slice che usa memmove per spostare gli oggetti molto più velocemente di quanto tu possa mai fare con Python, ma per lunghi elenchi richiede ancora molto tempo. Vedi github.com/python/cpython/blob/master/Objects/listobject.c e wiki.python.org/moin/TimeComplexity
DRayX

Grazie per il tempismo (e commenti @emu). Quindi possiamo dire che l.append(l.pop(0))è il migliore per spostare gli elenchi brevi (circa 7 elementi) di uno?
Lupo,

Ancora una volta, per l.append(l.pop(0))quanto riguarda una risposta: questa domanda è chiusa come duplicato. Forse voterai per riaprirlo?
Lupo,

8

Mi sono anche interessato a questo e ho confrontato alcune delle soluzioni suggerite con perfplot (un mio piccolo progetto).

Si scopre che

for _ in range(n):
    data.append(data.pop(0))

è di gran lunga il metodo più veloce per i piccoli turnin .

Per più grandi n,

data[n:] + data[:n]

non è male.

In sostanza, perfplot esegue il turno per aumentare le matrici di grandi dimensioni e misura il tempo. Ecco i risultati:

shift = 1:

inserisci qui la descrizione dell'immagine

shift = 100:

inserisci qui la descrizione dell'immagine


Codice per riprodurre la trama:

import numpy
import perfplot
import collections


shift = 100


def list_append(data):
    return data[shift:] + data[:shift]


def shift_concatenate(data):
    return numpy.concatenate([data[shift:], data[:shift]])


def roll(data):
    return numpy.roll(data, -shift)


def collections_deque(data):
    items = collections.deque(data)
    items.rotate(-shift)
    return items


def pop_append(data):
    for _ in range(shift):
        data.append(data.pop(0))
    return data


perfplot.save(
    "shift100.png",
    setup=lambda n: numpy.random.rand(n).tolist(),
    kernels=[list_append, roll, shift_concatenate, collections_deque, pop_append],
    n_range=[2 ** k for k in range(7, 20)],
    logx=True,
    logy=True,
    xlabel="len(data)",
)

Bel strumento che hai costruito. Per l.append(l.pop(0))quanto riguarda una risposta: questa domanda è chiusa come duplicato. Forse voterai per riaprirlo?
Lupo,

4

Forse un ringbuffer è più adatto. Non è un elenco, anche se è probabile che possa comportarsi abbastanza come un elenco per i tuoi scopi.

Il problema è che l'efficienza di uno spostamento su un elenco è O (n), che diventa significativo per elenchi abbastanza grandi.

Spostare in un ringbuffer è semplicemente aggiornare la posizione della testa che è O (1)


4

Per un'implementazione immutabile, potresti usare qualcosa del genere:

def shift(seq, n):
    shifted_seq = []
    for i in range(len(seq)):
        shifted_seq.append(seq[(i-n) % len(seq)])
    return shifted_seq

print shift([1, 2, 3, 4], 1)

3

Se l'efficienza è il tuo obiettivo, (cicli? Memoria?) Potresti essere meglio guardando il modulo array: http://docs.python.org/library/array.html

Le matrici non hanno il sovraccarico delle liste.

Per quanto riguarda gli elenchi puri, quello che hai è buono come puoi sperare di fare.


3

Penso che tu stia cercando questo:

a.insert(0, x)

Non vedo la relazione tra la domanda e la tua risposta. Puoi per favore spiegarlo?
Lupo,

2

Un'altra alternativa:

def move(arr, n):
    return [arr[(idx-n) % len(arr)] for idx,_ in enumerate(arr)]

1

Prendo questo modello di costo come riferimento:

http://scripts.mit.edu/~6.006/fall07/wiki/index.php?title=Python_Cost_Model

Il metodo utilizzato per dividere l'elenco e concatenare due elenchi secondari sono operazioni a tempo lineare. Suggerirei di usare pop, che è un'operazione a tempo costante, ad esempio:

def shift(list, n):
    for i in range(n)
        temp = list.pop()
        list.insert(0, temp)

2
aggiornamento: prendi questo come riferimento migliore: wiki.python.org/moin/TimeComplexity , usa collections.dequeuepop e appendleft, che sono entrambi O (1) ops. Nella mia prima risposta sopra, inserire è O (n).
Herrfz,

1
dovrebbe esserecollections.deque
herrfz il

1

Non so se sia "efficiente", ma funziona anche:

x = [1,2,3,4]
x.insert(0,x.pop())

EDIT: Ciao di nuovo, ho appena trovato un grosso problema con questa soluzione! Considera il seguente codice:

class MyClass():
    def __init__(self):
        self.classlist = []

    def shift_classlist(self): # right-shift-operation
        self.classlist.insert(0, self.classlist.pop())

if __name__ == '__main__':
    otherlist = [1,2,3]
    x = MyClass()

    # this is where kind of a magic link is created...
    x.classlist = otherlist

    for ii in xrange(2): # just to do it 2 times
        print '\n\n\nbefore shift:'
        print '     x.classlist =', x.classlist
        print '     otherlist =', otherlist
        x.shift_classlist() 
        print 'after shift:'
        print '     x.classlist =', x.classlist
        print '     otherlist =', otherlist, '<-- SHOULD NOT HAVE BIN CHANGED!'

Il metodo shift_classlist () esegue lo stesso codice di my x.insert (0, x.pop ()) - soluzione, otherlist è un elenco indipendente dalla classe. Dopo aver passato il contenuto di otherlist all'elenco MyClass.classlist, la chiamata a shift_classlist () modifica anche l'elenco di otherlist:

USCITA DELLA CONSOLLE:

before shift:
     x.classlist = [1, 2, 3]
     otherlist = [1, 2, 3]
after shift:
     x.classlist = [3, 1, 2]
     otherlist = [3, 1, 2] <-- SHOULD NOT HAVE BIN CHANGED!



before shift:
     x.classlist = [3, 1, 2]
     otherlist = [3, 1, 2]
after shift:
     x.classlist = [2, 3, 1]
     otherlist = [2, 3, 1] <-- SHOULD NOT HAVE BIN CHANGED!

Uso Python 2.7. Non so se sia un bug, ma penso sia più probabile che abbia capito male qualcosa qui.

Qualcuno di voi sa perché questo accade?


2
Ciò accade perché x.classlist = otherlistfa x.classlistriferimento allo stesso elenco di otherliste quindi quando lo chiami x.shift_classlist()muta l'elenco e perché entrambi i nomi si riferiscono allo stesso oggetto elenco. Entrambi i nomi sembrano cambiare perché sono solo alias per lo stesso oggetto. Utilizzare x.classlist = otherlist[:]invece per assegnare una copia dell'elenco.
Dan D.

Ehi wow! Grazie mille! Non lo sapevo davvero ed è davvero bello saperlo! :)
wese3112,

1

Il seguente metodo è O (n) in atto con memoria ausiliaria costante:

def rotate(arr, shift):
  pivot = shift % len(arr)
  dst = 0
  src = pivot
  while (dst != src):
    arr[dst], arr[src] = arr[src], arr[dst]
    dst += 1
    src += 1
    if src == len(arr):
      src = pivot
    elif dst == pivot:
      pivot = src

Nota che in Python questo approccio è orribilmente inefficiente rispetto ad altri in quanto non può sfruttare le implementazioni native di nessuno dei pezzi.


bene, in realtà potresti usare list.pop e list.append. Non è colpa della lingua che hai scritto una funzione a 12 righe che è O (n), quando avresti potuto semplicemente scrivere "l.append (l.pop (0))" che è tempo costante.
Purrell,

l.append (l.pop (0)) è O (n) (l.pop (0) deve spostare ogni elemento), quindi se si desidera spostare m valori la complessità è in realtà O (n * m). La complessità dell'algoritmo che ho fornito è O (n) indipendentemente dal numero di turni. In pratica, questo è lento perché tanta logica viene eseguita nelle operazioni di Python invece che in C (list.pop è implementato in c, vedere github.com/python/cpython/blob/master/Objects/listobject.c ).
DRayX,

1

Ho una cosa simile. Ad esempio, per spostare di due ...

def Shift(*args):
    return args[len(args)-2:]+args[:len(args)-2]

1

Penso che tu abbia il modo più efficiente

def shift(l,n):
    n = n % len(l)  
    return l[-U:] + l[:-U]

0

Qual è il caso d'uso? Spesso, in realtà non abbiamo bisogno di un array completamente spostato, dobbiamo solo accedere a una manciata di elementi nell'array spostato.

Ottenere sezioni Python è runtime O (k) dove k è la sezione, quindi una rotazione suddivisa è runtime N. Anche il comando di rotazione deque è O (k). Possiamo fare di meglio?

Considera un array estremamente grande (diciamo, così grande da computazionalmente lento da dividerlo). Una soluzione alternativa sarebbe quella di lasciare da solo l'array originale e semplicemente calcolare l'indice dell'articolo che sarebbe esistito nel nostro indice desiderato dopo uno spostamento di qualche tipo.

L'accesso a un elemento spostato diventa quindi O (1).

def get_shifted_element(original_list, shift_to_left, index_in_shifted):
    # back calculate the original index by reversing the left shift
    idx_original = (index_in_shifted + shift_to_left) % len(original_list)
    return original_list[idx_original]

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

print get_shifted_element(my_list, 1, 2) ----> outputs 4

print get_shifted_element(my_list, -2, 3) -----> outputs 2 

0

La funzione seguente copia l'elenco inviato in un elenco temp, in modo che la funzione pop non influisca sull'elenco originale:

def shift(lst, n, toreverse=False):
    templist = []
    for i in lst: templist.append(i)
    if toreverse:
        for i in range(n):  templist = [templist.pop()]+templist
    else:
        for i in range(n):  templist = templist+[templist.pop(0)]
    return templist

test:

lst = [1,2,3,4,5]
print("lst=", lst)
print("shift by 1:", shift(lst,1))
print("lst=", lst)
print("shift by 7:", shift(lst,7))
print("lst=", lst)
print("shift by 1 reverse:", shift(lst,1, True))
print("lst=", lst)
print("shift by 7 reverse:", shift(lst,7, True))
print("lst=", lst)

Produzione:

lst= [1, 2, 3, 4, 5]
shift by 1: [2, 3, 4, 5, 1]
lst= [1, 2, 3, 4, 5]
shift by 7: [3, 4, 5, 1, 2]
lst= [1, 2, 3, 4, 5]
shift by 1 reverse: [5, 1, 2, 3, 4]
lst= [1, 2, 3, 4, 5]
shift by 7 reverse: [4, 5, 1, 2, 3]
lst= [1, 2, 3, 4, 5]

0

Jon Bentley in Programming Pearls (Colonna 2) descrive un algoritmo elegante ed efficiente per ruotare un nvettore di elementi xlasciato dalle iposizioni:

Vediamo il problema come trasformazione dell'array abnell'array ba, ma supponiamo anche che abbiamo una funzione che inverte gli elementi in una porzione specifica dell'array. A partire da ab, invertiamo aper ottenere , invertiamo per ottenere , quindi invertiamo tutto per ottenere , che è esattamente . Ciò comporta il seguente codice per la rotazione:arbbarbr(arbr)rba

reverse(0, i-1)
reverse(i, n-1)
reverse(0, n-1)

Questo può essere tradotto in Python come segue:

def rotate(x, i):
    i %= len(x)
    x[:i] = reversed(x[:i])
    x[i:] = reversed(x[i:])
    x[:] = reversed(x)
    return x

demo:

>>> def rotate(x, i):
...     i %= len(x)
...     x[:i] = reversed(x[:i])
...     x[i:] = reversed(x[i:])
...     x[:] = reversed(x)
...     return x
... 
>>> rotate(list('abcdefgh'), 1)
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'a']
>>> rotate(list('abcdefgh'), 3)
['d', 'e', 'f', 'g', 'h', 'a', 'b', 'c']
>>> rotate(list('abcdefgh'), 8)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> rotate(list('abcdefgh'), 9)
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'a']

0

Per un elenco X = ['a', 'b', 'c', 'd', 'e', 'f']e un valore di spostamento desiderato shift inferiore alla lunghezza dell'elenco , possiamo definire la funzione list_shift()come di seguito

def list_shift(my_list, shift):
    assert shift < len(my_list)
    return my_list[shift:] + my_list[:shift]

Esempi,

list_shift(X,1)ritorni ['b', 'c', 'd', 'e', 'f', 'a'] list_shift(X,3)ritorni['d', 'e', 'f', 'a', 'b', 'c']


1
Questo è esattamente ciò che ha l'OP. Hai appena cambiato i nomi e aggiunto un'asserzione.
RufusVS

La funzione list_shiftnella tua risposta è identica alla funzione shiftnella domanda originale, quindi questa non è una risposta alla domanda reale: "C'è un modo migliore?"
RufusVS,

0
def solution(A, K):
    if len(A) == 0:
        return A

    K = K % len(A)

    return A[-K:] + A[:-K]

# use case
A = [1, 2, 3, 4, 5, 6]
K = 3
print(solution(A, K))

Ad esempio, dato

A = [3, 8, 9, 7, 6]
K = 3

la funzione dovrebbe tornare [9, 7, 6, 3, 8]. Sono state fatte tre rotazioni:

[3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7]
[6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9]
[7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8]

Per un altro esempio, dato

A = [0, 0, 0]
K = 1

la funzione dovrebbe tornare [0, 0, 0]

Dato

A = [1, 2, 3, 4]
K = 4

la funzione dovrebbe tornare [1, 2, 3, 4]


0

Stavo cercando una soluzione a questo problema. Questo risolve lo scopo in O (k).

def solution(self, list, k):
    r=len(list)-1
    i = 0
    while i<k:
        temp = list[0]
        list[0:r] = list[1:r+1]
        list[r] = temp
        i+=1
    return list

-3

per funzionalità simili a quelle del turno in altre lingue:

def shift(l):
    x = l[0]
    del(l[0])
    return x

1
-1: Questo sta facendo qualcosa di diverso da ciò che viene chiesto e BTW equivale anche aL.pop(0)
6502
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.