Un moyen efficace de faire pivoter une liste en python

263

Quelle est la façon la plus efficace de faire pivoter une liste en python? En ce moment, j'ai quelque chose comme ça:

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

Y a-t-il une meilleure façon?

dzhelil
la source
12
Ce n'est pas vraiment un changement car les autres langages (Perl, Ruby) utilisent le terme. C'est tourner. Peut-être que la question devrait être mise à jour en conséquence?
Vincent Fourmond
@dzhelil J'aime vraiment votre solution originale car elle n'introduit pas de mutations
juanchito
2
numpy.roll
BoltzmannBrain
2
Je pense que rotatec'est le bon mot, non shift.
codeforester
2
La vraie bonne réponse, c'est que vous ne devriez jamais faire tourner la liste en premier lieu. Créez une variable "pointeur" à l'endroit logique de votre liste où vous souhaitez que la "tête" ou la "queue" soit, et modifiez cette variable au lieu de déplacer l'un des éléments de la liste. Recherchez l'opérateur "modulo"% pour le moyen efficace de "boucler" votre pointeur au début et à la fin de la liste.
Cnd

Réponses:

280

A collections.dequeest optimisé pour tirer et pousser sur les deux extrémités. Ils ont même une rotate()méthode dédiée .

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
la source
8
Pour les futurs lecteurs: collections.deque rotate()est plus rapide que le découpage selon wiki.python.org/moin/TimeComplexity
Geoff
2
Mais sachez que l'utilisation deque.rotatenécessite d'abord une conversion de type en dequeobjet, qui est plus lente que l.append(l.pop(0)). Donc, si vous avez un objet deque pour commencer, c'est le plus rapide. Sinon, utilisez l.append(l.pop(0)).
Purrell
8
Pour élaborer, deque.rotateest O (k) mais la conversion de type de liste en deque est O (n) . Donc, si vous commencez avec une liste, utiliser deque.rotate est O (n) + O (k) = O (n). l.append(l.pop(0))d'autre part est O (1).
Purrell
3
@Purrell, le premier élément est O (n). Dans wiki.python.org/moin/TimeComplexity, il est répertorié comme O (k), et k est le nombre d'éléments dans la liste qui suit l'élément sauté, car la structure de données déplace tous les éléments suivants vers le début de la liste. Seul le dernier élément peut être sauté en temps O (1) pour cette raison.
Kirk Boyer
88

Qu'en est-il simplement d'utiliser pop(0)?

list.pop([i])

Retirez l'élément à la position donnée dans la liste et renvoyez-le. Si aucun index n'est spécifié, a.pop()supprime et renvoie le dernier élément de la liste. (Les crochets autour ide la signature de méthode indiquent que le paramètre est facultatif, pas que vous devez taper des crochets à cette position. Vous verrez cette notation fréquemment dans la référence de bibliothèque Python.)

Jamgold
la source
16
Mais cela ne coûterait-il pas O (k) pour supprimer chaque élément de la liste où k est le nombre d'éléments restants. Le temps total sera donc O (n ^ 2) wiki.python.org/moin/TimeComplexity
Pramod
5
Cela ne répond pas vraiment à la question. La question n'est pas de retourner les articles dans l'ordre, mais plutôt de créer une nouvelle liste dans un ordre différent.
user650261
5
non, la réponse à la question en utilisant pop serait l.append(l.pop(0). Si je ne me trompe pas, c'est O (1).
Purrell
4
list.pop appelle en interne list_ass_slice qui utilise memmove pour déplacer très rapidement tous les éléments, mais c'est toujours O (n). Voir github.com/python/cpython/blob/master/Objects/listobject.c et wiki.python.org/moin/TimeComplexity . Le seul élément qui peut être supprimé d'une liste python en temps constant est le dernier.
DRayX
2
Voté. Depuis docs.python.org/3/tutorial/… Il est également possible d'utiliser une liste comme file d'attente, où le premier élément ajouté est le premier élément récupéré («premier entré , premier sorti»); cependant, les listes ne sont pas efficaces à cette fin. Alors que les ajouts et les sauts de la fin de la liste sont rapides, les insertions ou les sauts du début d'une liste sont lents (car tous les autres éléments doivent être décalés d'un).
SantaXL
59

Numpy peut le faire en utilisant la rollcommande:

>>> 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])
Richard
la source
1
Ce que j'aime chez SO, c'est que parfois dans le fil des réponses, vous pouvez trouver de nouveaux trésors comme celui-ci :)
noamgot
Ceci, quand je l'ai testé, est très, très lent
Peter Harrison
@PeterHarrison: Puisque vous ne fournissez pas de détails sur les tests, il est difficile de savoir ce que vous voulez dire. Cette réponse fournit des détails de test complets et une comparaison temporelle.
Richard
33

Cela dépend de ce que vous voulez que vous ayez à faire:

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

Vous voudrez peut-être changer votre:

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

à:

def shift(seq, n):
    n = n % len(seq)
    return seq[n:] + seq[:n]
jcdyer
la source
5
NB: Cela plantera pour les listes vides.
meawoppl
n = n% len (seq) return = seq [-n:] + seq [: - n]
user3303020
Pouvez-vous expliquer pourquoi n = n% len (seq)?
AerysS
16

La façon la plus simple à laquelle je peux penser:

a.append(a.pop(0))
Thijs
la source
3
C'est le moyen le plus rapide pour les listes. collections.dequeest plus rapide mais pour les cas les plus courants de longueur de liste sur une seule itération, ou tout cas d'itérations multiples, a.append(a.pop(0))va être plus rapide que la conversion de type en deque
Purrell
@runDOSrun la réponse parfaite à cette question qui est malheureusement fermée en double. Peut-être voterez-vous pour sa réouverture?
Loup
15

Si vous souhaitez simplement parcourir ces ensembles d'éléments plutôt que de construire une structure de données distincte, envisagez d'utiliser des itérateurs pour construire une expression de générateur:

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
la source
11

Cela dépend également si vous souhaitez déplacer la liste en place (en la mutant) ou si la fonction doit renvoyer une nouvelle liste. Parce que, selon mes tests, quelque chose comme ça est au moins vingt fois plus rapide que votre implémentation qui ajoute deux listes:

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

En fait, même ajouter un l = l[:]en haut de celui-ci pour fonctionner sur une copie de la liste transmise est toujours deux fois plus rapide.

Diverses implémentations avec un certain timing sur http://gist.github.com/288272

keturn
la source
3
Au lieu de l[:n] = []j'irais pour del l[:n]. Juste une alternative.
tzot
1
Oh, ouais, bon vieux del. J'oublie souvent del; l'opération de liste qui est une déclaration, pas une méthode. Py3k a-t-il changé cette bizarrerie, ou l'avons-nous encore?
keturn
2
@keturn: delest toujours une déclaration dans Py3. Cependant x.__delitem__(y) <==> del x[y], si vous préférez utiliser des méthodes, il l.__delitem__(slice(n))est également équivalent et fonctionne à la fois en 2 et 3.
martineau
9

Juste quelques notes sur le timing:

Si vous commencez avec une liste, l.append(l.pop(0))c'est la méthode la plus rapide que vous pouvez utiliser. Cela peut être démontré avec la seule complexité du temps:

  • deque.rotate est O (k) (k = nombre d'éléments)
  • la conversion de la liste en deque est O (n)
  • list.append et list.pop sont tous deux O (1)

Donc, si vous commencez avec des dequeobjets, vous pouvez le faire deque.rotate()au prix de O (k). Mais, si le point de départ est une liste, la complexité temporelle de l'utilisation deque.rotate()est O (n). l.append(l.pop(0)est plus rapide à O (1).

Juste à titre d'illustration, voici quelques exemples de timings sur les itérations 1M:

Méthodes qui nécessitent une conversion de type:

  • deque.rotateavec objet deque: 0,12380790710449219 secondes (le plus rapide)
  • deque.rotateavec conversion de type: 6,853878974914551 secondes
  • np.rollavec nparray: 6.0491721630096436 secondes
  • np.rollavec conversion de type: 27,558452129364014 secondes

Liste des méthodes mentionnées ici:

  • l.append(l.pop(0)): 0,32483696937561035 secondes (le plus rapide)
  • " shiftInPlace": 4,819645881652832 secondes
  • ...

Le code temporel utilisé est ci-dessous.


collections.deque

Montrer que la création de deques à partir de listes est 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 vous devez créer des objets deque:

1M itérations @ 6,853878974914551 secondes

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 vous avez déjà des objets deque:

1M itérations @ 0,12380790710449219 secondes

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 vous devez créer des nparrays

1M itérations @ 27,558452129364014 secondes

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 vous avez déjà des nparrays:

1M itérations @ 6.0491721630096436 secondes

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)

"Déplacer en place"

Ne nécessite aucune conversion de type

1M itérations @ 4.819645881652832 secondes

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

Ne nécessite aucune conversion de type

1M itérations @ 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
la source
2
tandis que list.pop () est une opération à temps constant, list.pop (0) ne l' est pas . Il s'exécute en temps linéaire par rapport à la longueur de la liste. Vous pouvez le tester en modifiant votre configuration de timeit:l = [random.random() for i in range(100000)]
emu
1
list.pop n'est pas une opération à temps constant. list.pop s'exécute en temps O (k) où k est le nombre d'éléments après l'élément supprimé, donc list.pop (0) est O (n). En interne, list.pop utilise list_ass_slice qui utilise memmove pour déplacer les éléments beaucoup plus rapidement que vous ne le pourriez avec python, mais pour les longues listes, cela prend encore beaucoup de temps. Voir github.com/python/cpython/blob/master/Objects/listobject.c et wiki.python.org/moin/TimeComplexity
DRayX
Merci pour le timing (et commentaires @emu). Alors, pouvons-nous dire que l.append(l.pop(0))c'est le meilleur moyen de décaler les listes courtes (environ 7 éléments) d'un?
Loup
Encore une fois, concernant l.append(l.pop(0))comme réponse: Cette question est fermée en double. Peut-être voterez-vous pour sa réouverture?
Loup
8

Je me suis également intéressé à cela et j'ai comparé certaines des solutions suggérées avec perfplot (un petit projet à moi).

Il se trouve que

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

est de loin la méthode la plus rapide pour les petites équipes n.

Pour les plus grands n,

data[n:] + data[:n]

n'est pas mauvais.

Essentiellement, perfplot effectue le changement pour augmenter les grands tableaux et mesure le temps. Voici les résultats:

shift = 1:

entrez la description de l'image ici

shift = 100:

entrez la description de l'image ici


Code pour reproduire l'intrigue:

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
la source
Bel outil que vous avez construit. Concernant l.append(l.pop(0))comme réponse: Cette question est fermée en double. Peut-être voterez-vous pour sa réouverture?
Wolf
4

Peut-être qu'un ringbuffer est plus approprié. Ce n'est pas une liste, bien qu'il soit probable qu'elle puisse se comporter assez comme une liste pour vos besoins.

Le problème est que l'efficacité d'un décalage sur une liste est O (n), ce qui devient significatif pour des listes suffisamment grandes.

Le passage dans un ringbuffer met simplement à jour l'emplacement de la tête qui est O (1)

John La Rooy
la source
4

Pour une implémentation immuable, vous pouvez utiliser quelque chose comme ceci:

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
la source
3

Si l'efficacité est votre objectif, (cycles? Mémoire?), Vous feriez peut-être mieux de regarder le module de tableau: http://docs.python.org/library/array.html

Les tableaux n'ont pas la surcharge des listes.

En ce qui concerne les listes pures, ce que vous avez est aussi bon que vous pouvez l'espérer.

récursif
la source
3

Je pense que vous cherchez ceci:

a.insert(0, x)
redreamality
la source
Je ne vois pas la relation entre la question et votre réponse. Pouvez-vous l'expliquer?
Wolf
2

Une autre alternative:

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

Je prends ce modèle de coût comme référence:

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

Votre méthode de découpage de la liste et de concaténation de deux sous-listes est une opération à temps linéaire. Je suggère d'utiliser pop, qui est une opération à temps constant, par exemple:

def shift(list, n):
    for i in range(n)
        temp = list.pop()
        list.insert(0, temp)
herrfz
la source
2
mise à jour: prenez cela comme une meilleure référence: wiki.python.org/moin/TimeComplexity , utilisez collections.dequeuepop et appendleft, qui sont tous les deux O (1) ops. Dans ma première réponse ci-dessus, insérer est O (n).
herrfz
1
devrait êtrecollections.deque
herrfz
1

Je ne sais pas si c'est «efficace», mais ça marche aussi:

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

EDIT: Bonjour encore une fois, je viens de trouver un gros problème avec cette solution! Considérez le code suivant:

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

La méthode shift_classlist () exécute le même code que ma solution x.insert (0, x.pop ()) - otherlist est une liste indépendante de la classe. Après avoir transmis le contenu de l'autre liste à la liste MyClass.classlist, l'appel de shift_classlist () modifie également l'autre liste:

SORTIE CONSOLE:

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!

J'utilise Python 2.7. Je ne sais pas si c'est un bug, mais je pense qu'il est plus probable que j'ai mal compris quelque chose ici.

Est-ce que quelqu'un d'entre vous sait pourquoi cela se produit?

wese3112
la source
2
Cela se produit parce que x.classlist = otherlistfait x.classlistréférence à la même liste otherlist, puis lorsque vous l'appelez, x.shift_classlist()il mute la liste et parce que les deux noms font référence au même objet de liste. Les deux noms semblent changer car ce ne sont que des alias pour le même objet. Utilisez x.classlist = otherlist[:]plutôt pour attribuer une copie de la liste.
Dan D.
Hé wow! Merci beaucoup! Je ne le savais vraiment pas et c'est vraiment bon de savoir! :)
wese3112
1

La méthode suivante est O (n) en place avec une mémoire auxiliaire 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

Notez qu'en python, cette approche est horriblement inefficace par rapport aux autres car elle ne peut tirer parti des implémentations natives d'aucune des pièces.

DRayX
la source
eh bien, en fait, vous pouvez utiliser list.pop et list.append. Ce n'est pas la faute du langage si vous avez écrit une fonction de 12 lignes qui est O (n), alors que vous auriez pu écrire "l.append (l.pop (0))" qui est à temps constant.
Purrell
l.append (l.pop (0)) est O (n) (l.pop (0) doit décaler chaque élément), donc si vous vouliez décaler m valeurs la complexité est en fait O (n * m). La complexité de l'algorithme que j'ai fourni est O (n) quel que soit le nombre de décalages. En pratique, cela est lent car beaucoup de logique est effectuée dans les opérations python au lieu de C (list.pop est implémenté en c, voir github.com/python/cpython/blob/master/Objects/listobject.c ).
DRayX
1

J'ai une chose similaire. Par exemple, pour décaler de deux ...

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

Je pense que vous avez le moyen le plus efficace

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

Quel est le cas d'utilisation? Souvent, nous n'avons pas réellement besoin d'un tableau entièrement décalé - nous avons juste besoin d'accéder à une poignée d'éléments dans le tableau décalé.

L'obtention de tranches Python est exécutée O (k) où k est la tranche, donc une rotation en tranches est exécutée N. La commande deque rotation est également O (k). Pouvons-nous faire mieux?

Considérons un tableau qui est extrêmement grand (disons, si grand qu'il serait lent à calculer pour le découper). Une solution alternative serait de laisser le tableau d'origine seul et de simplement calculer l'indice de l'élément qui aurait existé dans notre indice souhaité après un changement quelconque.

Accéder à un élément décalé devient ainsi 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
la source
0

La fonction suivante copie la liste envoyée à un templiste, afin que la fonction pop n'affecte pas la liste d'origine:

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

Essai:

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)

Production:

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
la source
0

Jon Bentley dans Programming Pearls (Colonne 2) décrit un algorithme élégant et efficace pour faire tourner un nvecteur -élément xlaissé par des ipositions:

Considérons le problème comme transformant le tableau aben tableau ba, mais supposons également que nous avons une fonction qui inverse les éléments dans une partie spécifiée du tableau. En commençant par ab, nous inversons apour obtenir , inversons pour obtenir , puis inversons le tout pour obtenir , ce qui est exactement . Il en résulte le code de rotation suivant:arbbarbr(arbr)rba

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

Cela peut être traduit en Python comme suit:

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

Démo:

>>> 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
la source
0

Pour une liste X = ['a', 'b', 'c', 'd', 'e', 'f']et une valeur de décalage souhaitée shift inférieure à la longueur de la liste , nous pouvons définir la fonction list_shift()comme ci-dessous

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

Exemples,

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

helcode
la source
1
C'est exactement ce que le PO a. Vous venez de changer les noms et ajouté une assertion.
RufusVS
La fonction list_shiftdans votre réponse est identique à la fonction shiftdans la question d'origine, donc ce n'est pas une réponse à la question réelle: "Y a-t-il une meilleure façon?"
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))

Par exemple, étant donné

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

la fonction devrait revenir [9, 7, 6, 3, 8]. Trois rotations ont été effectuées:

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

Pour un autre exemple, étant donné

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

la fonction devrait retourner [0, 0, 0]

Donné

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

la fonction devrait retourner [1, 2, 3, 4]

Rakesh Kumar
la source
0

Je cherchais une solution en place à ce problème. Cela résout le but de 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
la source
-3

pour des fonctionnalités similaires à celles des changements dans d'autres langues:

def shift(l):
    x = l[0]
    del(l[0])
    return x
David
la source
1
-1: Cela fait quelque chose de différent de ce qui est demandé, et BTW est également équivalent àL.pop(0)
6502