Manera eficiente de rotar una lista en Python

263

¿Cuál es la forma más eficiente de rotar una lista en Python? En este momento tengo algo como esto:

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

¿Hay una mejor manera?

dzhelil
fuente
12
Esto no es realmente un cambio ya que los otros idiomas (Perl, Ruby) usan el término. Esto es rotar. ¿Quizás la pregunta debería actualizarse en consecuencia?
Vincent Fourmond el
@dzhelil Me gusta mucho tu solución original porque no introduce mutaciones
juanchito
2
numpy.roll
BoltzmannBrain
2
Creo que rotatees la palabra correcta, no shift.
codeforester
2
La verdadera respuesta correcta es que nunca debes rotar la lista en primer lugar. Cree una variable "puntero" en el lugar lógico en su lista donde desea que esté la "cabeza" o la "cola", y cambie esa variable en lugar de mover cualquiera de los elementos de la lista. Busque el operador de "módulo"% para ver la forma eficiente de "ajustar" su puntero al inicio y al final de la lista.
cnd

Respuestas:

280

A collections.dequeestá optimizado para tirar y empujar en ambos extremos. Incluso tienen un rotate()método dedicado .

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]
Ignacio Vazquez-Abrams
fuente
8
Para futuros lectores: collections.deque rotate()es más rápido que cortar según wiki.python.org/moin/TimeComplexity
Geoff
2
Pero tenga en cuenta que usar primero deque.rotaterequiere una conversión de tipo a un dequeobjeto, que es más lento que l.append(l.pop(0)). Entonces, si tiene un objeto deque para comenzar, asegúrese de que sea el más rápido. De lo contrario, use l.append(l.pop(0)).
Purrell
8
Para elaborar, deque.rotatees O (k) pero la conversión de tipo de la lista a deque es O (n) . Entonces, si comienza con una lista, usar deque.rotate es O (n) + O (k) = O (n). l.append(l.pop(0))por otro lado es O (1).
Purrell
3
@Purrell, haciendo estallar el elemento frontal es O (n). En wiki.python.org/moin/TimeComplexity aparece como O (k), yk es el número de elementos en la lista que sigue al elemento emergente, porque la estructura de datos desplaza todos los elementos siguientes hacia el frente de la lista. Solo el último elemento puede aparecer en tiempo O (1) por este motivo.
Kirk Boyer
88

¿Qué hay de solo usar pop(0)?

list.pop([i])

Elimine el elemento en la posición dada en la lista y devuélvalo. Si no se especifica ningún índice, a.pop()elimina y devuelve el último elemento de la lista. (Los corchetes alrededor ide la firma del método indican que el parámetro es opcional, no que debe escribir corchetes en esa posición. Verá esta notación con frecuencia en la Referencia de la biblioteca de Python).

Jamgold
fuente
16
Pero no le costaría a O (k) eliminar cada elemento de la lista donde k es el número de elementos restantes. Entonces, el tiempo total será O (n ^ 2) wiki.python.org/moin/TimeComplexity
Pramod
55
Esto realmente no responde la pregunta. La pregunta no se trata de devolver los artículos en orden, sino de crear una nueva lista que esté en un orden diferente.
user650261
55
no, la respuesta a la pregunta usando pop sería l.append(l.pop(0). Que si no me equivoco es O (1).
Purrell
44
list.pop llama internamente a list_ass_slice, que usa memmove para mover rápidamente todos los elementos, pero sigue siendo O (n). Consulte github.com/python/cpython/blob/master/Objects/listobject.c y wiki.python.org/moin/TimeComplexity . El único elemento que se puede eliminar de una lista de Python en tiempo constante es el último.
DRayX
2
Voto negativo Desde docs.python.org/3/tutorial/… También es posible utilizar una lista como una cola, donde el primer elemento agregado es el primer elemento recuperado ("primero en entrar , primero en salir"); sin embargo, las listas no son eficientes para este propósito. Si bien los anexos y los estallidos desde el final de la lista son rápidos, hacer inserciones o estallidos desde el comienzo de una lista es lento (porque todos los demás elementos deben ser desplazados por uno).
SantaXL
59

Numpy puede hacer esto usando el 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])
Ricardo
fuente
1
Lo que amo de SO es que a veces las respuestas alimentan usted puede encontrar algunos grandes nuevos tesoros como éste :)
noamgot
Esto, cuando lo probé, es muy, muy lento
Peter Harrison
@PeterHarrison: como no proporcionas detalles de las pruebas, es difícil saber a qué te refieres. Esta respuesta proporciona detalles completos de las pruebas y una comparación de tiempos.
Richard
33

Depende de lo que quieras que suceda cuando hagas esto:

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

Es posible que desee cambiar su:

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

a:

def shift(seq, n):
    n = n % len(seq)
    return seq[n:] + seq[:n]
jcdyer
fuente
55
NB: Esto se bloqueará por listas vacías.
meawoppl
n = n% len (seq) return = seq [-n:] + seq [: - n]
user3303020
¿Puedes explicar por qué n = n% len (seq)?
AerysS
16

La forma más simple en que puedo pensar:

a.append(a.pop(0))
Thijs
fuente
3
Esta es la forma más rápida para las listas. collections.dequees más rápido pero para la mayoría de los casos comunes de longitud de lista en una sola iteración, o cualquier caso de iteraciones múltiples, a.append(a.pop(0))será más rápido que la conversión de tipo a deque
Purrell
@runDOS Ejecuta la respuesta perfecta a esta pregunta que está tristemente cerrada como un duplicado. ¿Quizás votarás por reabrirlo?
Wolf
15

Si solo desea iterar sobre estos conjuntos de elementos en lugar de construir una estructura de datos separada, considere usar iteradores para construir una expresión generadora:

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

>>> list(shift([1,2,3],1))
[2, 3, 1]
Phil H
fuente
11

Esto también depende de si desea cambiar la lista en su lugar (mutarla) o si desea que la función devuelva una nueva lista. Porque, según mis pruebas, algo como esto es al menos veinte veces más rápido que su implementación que agrega dos listas:

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

De hecho, incluso agregar un l = l[:]encabezado para operar en una copia de la lista aprobada sigue siendo el doble de rápido.

Diversas implementaciones con algo de tiempo en http://gist.github.com/288272

keturn
fuente
3
En lugar de l[:n] = []ir por del l[:n]. Solo una alternativa.
tzot
1
Oh, sí, buen viejo del. A menudo me olvido de del; La operación de lista es una declaración, no un método. ¿Py3k cambió ese capricho o todavía lo tenemos?
keturn
2
@keturn: delsigue siendo una declaración en Py3. Sin embargo x.__delitem__(y) <==> del x[y], por lo que, si lo prefiere, utilizando métodos, l.__delitem__(slice(n))también es equivalente y funciona tanto en 2 y 3.
martineau
9

Solo algunas notas sobre el tiempo:

Si está comenzando con una lista, l.append(l.pop(0))es el método más rápido que puede usar. Esto se puede mostrar solo con la complejidad del tiempo:

  • deque.rotate es O (k) (k = número de elementos)
  • la lista para eliminar la conversión es O (n)
  • list.append y list.pop son O (1)

Entonces, si está comenzando con dequeobjetos, puede hacerlo deque.rotate()a costa de O (k). Pero, si el punto de partida es una lista, la complejidad temporal del uso deque.rotate()es O (n). l.append(l.pop(0)es más rápido en O (1).

Solo por el bien de la ilustración, aquí hay algunos tiempos de muestra en iteraciones de 1M:

Métodos que requieren conversión de tipo:

  • deque.rotatecon objeto de deque: 0.12380790710449219 segundos (el más rápido)
  • deque.rotatecon conversión de tipo: 6.853878974914551 segundos
  • np.rollcon nparray: 6.0491721630096436 segundos
  • np.rollcon conversión de tipo: 27.558452129364014 segundos

Enumere los métodos mencionados aquí:

  • l.append(l.pop(0)): 0.32483696937561035 segundos (el más rápido)
  • " shiftInPlace": 4.819645881652832 segundos
  • ...

El código de tiempo utilizado se encuentra a continuación.


colecciones.deque

Mostrando que la creación de deques de listas es 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

Si necesita crear objetos deque:

1 millón de iteraciones @ 6.853878974914551 segundos

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)

Si ya tiene objetos deque:

1M iteraciones @ 0.12380790710449219 segundos

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

Si necesita crear nparrays

1 millón de iteraciones @ 27.558452129364014 segundos

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

Si ya tiene nparrays:

1 millón de iteraciones a 6.0491721630096436 segundos

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)

"Cambio en el lugar"

No requiere conversión de tipo

1 millón de iteraciones a 4.819645881652832 segundos

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

No requiere conversión de tipo

1M iteraciones @ 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)
Purrell
fuente
2
mientras list.pop () es una operación de tiempo constante, list.pop (0) no lo es . Se ejecuta en tiempo lineal con respecto a la longitud de la lista. Puede probar eso modificando su configuración de timeit:l = [random.random() for i in range(100000)]
emu
1
list.pop no es una operación de tiempo constante. list.pop se ejecuta en tiempo O (k) donde k es el número de elementos que pasan el elemento eliminado, por lo que list.pop (0) es O (n). Internamente, list.pop usa list_ass_slice, que usa memmove para mover elementos mucho más rápido de lo que podría hacerlo con python, pero para listas largas todavía lleva mucho tiempo. Ver github.com/python/cpython/blob/master/Objects/listobject.c y wiki.python.org/moin/TimeComplexity
DRayX
Gracias por el tiempo (y comentarios @emu). Entonces, ¿podemos decir que l.append(l.pop(0))es el mejor rendimiento para cambiar listas cortas (alrededor de 7 elementos) por uno?
Wolf
Nuevamente, preocupante l.append(l.pop(0))como respuesta: esta pregunta se cierra como un duplicado. ¿Quizás votarás por reabrirlo?
Wolf
8

También me interesé en esto y comparé algunas de las soluciones sugeridas con perfplot (un pequeño proyecto mío).

Resulta que

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

es, con mucho, el método más rápido para pequeños turnos n.

Para más grande n,

data[n:] + data[:n]

no está mal

Esencialmente, perfplot realiza el cambio para aumentar matrices grandes y mide el tiempo. Aquí están los resultados:

shift = 1:

ingrese la descripción de la imagen aquí

shift = 100:

ingrese la descripción de la imagen aquí


Código para reproducir 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)",
)
Nico Schlömer
fuente
Buena herramienta que construiste. En l.append(l.pop(0))cuanto a una respuesta: esta pregunta se cierra como un duplicado. ¿Quizás votarás por reabrirlo?
Wolf
4

Posiblemente un ringbuffer sea más adecuado. No es una lista, aunque es probable que pueda comportarse lo suficiente como una lista para sus propósitos.

El problema es que la eficiencia de un cambio en una lista es O (n), que se vuelve significativa para listas lo suficientemente grandes.

Cambiar en un ringbuffer es simplemente actualizar la ubicación del cabezal, que es O (1)

John La Rooy
fuente
4

Para una implementación inmutable, puede usar algo como esto:

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)
Bittercoder
fuente
3

Si su objetivo es la eficiencia (¿ciclos? ¿Memoria?), Es mejor que mire el módulo de matriz: http://docs.python.org/library/array.html

Las matrices no tienen la sobrecarga de las listas.

Sin embargo, en lo que respecta a las listas puras, lo que tiene es tan bueno como puede esperar hacer.

recursivo
fuente
3

Creo que estás buscando esto:

a.insert(0, x)
redreamalidad
fuente
No veo la relación entre la pregunta y su respuesta. ¿Puedes por favor explicarlo?
Wolf
2

Otra alternativa:

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

Tomo este modelo de costos como referencia:

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

Su método de segmentar la lista y concatenar dos sublistas son operaciones de tiempo lineal. Sugeriría usar pop, que es una operación de tiempo constante, por ejemplo:

def shift(list, n):
    for i in range(n)
        temp = list.pop()
        list.insert(0, temp)
herrfz
fuente
2
actualización: tome esto como una mejor referencia: wiki.python.org/moin/TimeComplexity , use collections.dequeuepop y appendleft, que son O (1) ops. En mi primera respuesta anterior, insertar es O (n).
herrfz
1
debería sercollections.deque
herrfz
1

No sé si esto es 'eficiente', pero también funciona:

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

EDITAR: Hola de nuevo, ¡acabo de encontrar un gran problema con esta solución! Considere el siguiente código:

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!'

El método shift_classlist () ejecuta el mismo código que mi solución x.insert (0, x.pop ()), otherlist es una lista independiente de la clase. Después de pasar el contenido de otherlist a la lista MyClass.classlist, llamar a shift_classlist () también cambia la lista otherlist:

CONSOLA DE SALIDA:

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!

Yo uso Python 2.7. No sé si eso es un error, pero creo que es más probable que haya entendido mal algo aquí.

¿Alguien de ustedes sabe por qué sucede esto?

wese3112
fuente
2
Eso sucede porque x.classlist = otherlisthace que se haga x.classlistreferencia a la misma lista otherlisty luego, cuando la llamas x.shift_classlist(), muta la lista y porque ambos nombres se refieren al mismo objeto de lista. Ambos nombres parecen cambiar porque son solo alias para el mismo objeto. Use en su x.classlist = otherlist[:]lugar para asignar una copia de la lista.
Dan D.
Hola guau! ¡Muchas gracias! ¡Realmente no lo sabía y es realmente bueno saberlo! :)
wese3112 17/1013
1

El siguiente método es O (n) en su lugar con memoria auxiliar constante:

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

Tenga en cuenta que en python, este enfoque es terriblemente ineficiente en comparación con otros, ya que no puede aprovechar las implementaciones nativas de ninguna de las piezas.

DRayX
fuente
bueno, en realidad podrías usar list.pop y list.append. No es culpa del lenguaje que haya escrito una función de 12 líneas que es O (n), cuando podría haber escrito "l.append (l.pop (0))", que es tiempo constante.
Purrell
l.append (l.pop (0)) es O (n) (l.pop (0) tiene que cambiar cada elemento), por lo tanto, si desea cambiar los valores de m, la complejidad es en realidad O (n * m). La complejidad del algoritmo que proporcioné es O (n) independientemente del número de cambios. En la práctica, esto es lento porque se hace mucha lógica en las operaciones de Python en lugar de C (list.pop se implementa en c, consulte github.com/python/cpython/blob/master/Objects/listobject.c ).
DRayX
1

Tengo algo similar Por ejemplo, para cambiar por dos ...

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

Creo que tienes la forma más eficiente

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

¿Cuál es el caso de uso? A menudo, en realidad no necesitamos una matriz totalmente desplazada, solo necesitamos acceder a un puñado de elementos en la matriz desplazada.

Obtener segmentos de Python es tiempo de ejecución O (k) donde k es el segmento, por lo que una rotación dividida es tiempo de ejecución N. El comando de rotación de eliminación también es O (k). ¿Podemos hacerlo mejor?

Considere una matriz que es extremadamente grande (digamos, tan grande que sería computacionalmente lenta dividirla). Una solución alternativa sería dejar solo la matriz original y simplemente calcular el índice del elemento que habría existido en nuestro índice deseado después de un cambio de algún tipo.

Acceder a un elemento desplazado se convierte así en 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 
Nick Lee
fuente
0

La siguiente función copia la lista enviada a un templista, de modo que la función emergente no afecta la lista original:

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

Pruebas:

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)

Salida:

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]
rnso
fuente
0

Jon Bentley en Programming Pearls (Columna 2) describe un algoritmo elegante y eficiente para rotar un nvector de elementos xdejado por las iposiciones:

Veamos el problema como transformar la matriz aben la matriz ba, pero también supongamos que tenemos una función que invierte los elementos en una porción específica de la matriz. Comenzando con ab, retrocedemos apara obtener , retrocedemos para obtener , y luego revertimos todo para obtener , que es exactamente . Esto da como resultado el siguiente código para la rotación:arbbarbr(arbr)rba

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

Esto se puede traducir a Python de la siguiente manera:

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

Manifestación:

>>> 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']
Eugene Yarmash
fuente
0

Para una lista X = ['a', 'b', 'c', 'd', 'e', 'f']y un valor de desplazamiento deseado shift menor que la longitud de la lista , podemos definir la función de la list_shift()siguiente manera

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

Ejemplos,

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

helcode
fuente
1
Eso es exactamente lo que tiene el OP. Acabas de cambiar los nombres y agregaste una afirmación.
RufusVS
La función list_shiften su respuesta es idéntica a la función shiften la pregunta original, por lo que esta no es una respuesta a la pregunta real: "¿Hay una mejor manera?"
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))

Por ejemplo, dado

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

la función debería volver [9, 7, 6, 3, 8]. Se hicieron tres rotaciones:

[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]

Para otro ejemplo, dado

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

la función debería volver [0, 0, 0]

Dado

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

la función debería volver [1, 2, 3, 4]

Rakesh Kumar
fuente
0

Estaba buscando una solución para este problema. Esto resuelve el propósito en 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
Ankit
fuente
-3

para una funcionalidad similar a shift en otros idiomas:

def shift(l):
    x = l[0]
    del(l[0])
    return x
David
fuente
1
-1: Esto está haciendo algo diferente de lo que se pide, y BTW también es equivalente aL.pop(0)
6502