736 votes

Quelle est la syntaxe idiomatique pour précéder une courte liste en Python ?

list.append() est le choix évident pour ajouter à la fin d'une liste. Voici une explication raisonnable pour les disparus list.prepend() . En supposant que ma liste soit courte et que les problèmes de performance soient négligeables, est-ce que

list.insert(0, x)

ou

list[0:0] = [x]

idiomatique ?

1028voto

Raymond Hettinger Points 50330

El s.insert(0, x) est la plus courante.

Cependant, chaque fois que vous le voyez, il est peut-être temps d'envisager d'utiliser une collections.deque au lieu d'une liste.

370voto

Nil Geisweiller Points 285

Si vous pouvez suivre la voie fonctionnelle, les points suivants sont assez clairs

new_list = [x] + your_list

Bien sûr, vous n'avez pas inséré x en your_list Vous avez plutôt créé une nouvelle liste avec x Prédestiné à cela.

132voto

Aaron Hall Points 7381

Quelle est la syntaxe idiomatique pour précéder une courte liste en Python ?

En général, en Python, vous n'avez pas envie d'ajouter de façon répétitive des éléments à une liste.

Si c'est court et que vous ne le faites pas souvent... alors c'est bon.

list.insert

El list.insert peut être utilisé de cette façon.

list.insert(0, x)

Mais c'est inefficace, car en Python, un fichier list est un tableau de pointeurs, et Python doit maintenant prendre chaque pointeur de la liste et le déplacer vers le bas d'une unité pour insérer le pointeur de votre objet dans le premier slot, donc ceci n'est vraiment efficace que pour des listes plutôt courtes, comme vous le demandez.

Voici un extrait à partir de la source CPython où cela est mis en œuvre - et comme vous pouvez le voir, nous commençons à la fin du tableau et nous déplaçons tout vers le bas d'une unité pour chaque insertion :

for (i = n; --i >= where; )
    items[i+1] = items[i];

Si vous voulez un conteneur/une liste qui est efficace pour ajouter des éléments, vous voulez une liste liée. Python dispose d'une liste doublement liée, qui permet d'insérer rapidement des éléments au début et à la fin de la liste - c'est ce qu'on appelle un deque .

deque.appendleft

A collections.deque possède plusieurs des méthodes d'une liste. list.sort est une exception, ce qui rend deque définitivement non entièrement substituable à Liskov list .

>>> set(dir(list)) - set(dir(deque))
{'sort'}

El deque a également un appendleft (ainsi que la méthode popleft ). Le site deque est une file d'attente à double extrémité et une liste doublement liée - quelle que soit sa longueur, il faut toujours le même temps pour préprendre quelque chose. En notation grand O, O(1) contre le temps O(n) pour les listes. Voici l'utilisation :

>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])

deque.extendleft

Il faut également tenir compte de l'élément deque extendleft qui précède de façon itérative :

>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])

Notez que chaque élément sera ajouté un par un, ce qui inversera leur ordre.

Performance de list contre deque

Tout d'abord, nous mettons en place un système itératif de préparation :

import timeit
from collections import deque

def list_insert_0():
    l = []
    for i in range(20):
        l.insert(0, i)

def list_slice_insert():
    l = []
    for i in range(20):
        l[:0] = [i]      # semantically same as list.insert(0, i)

def list_add():
    l = []
    for i in range(20):
        l = [i] + l      # caveat: new list each time

def deque_appendleft():
    d = deque()
    for i in range(20):
        d.appendleft(i)  # semantically same as list.insert(0, i)

def deque_extendleft():
    d = deque()
    d.extendleft(range(20)) # semantically same as deque_appendleft above

et les performances :

>>> min(timeit.repeat(list_insert_0))
2.8267281929729506
>>> min(timeit.repeat(list_slice_insert))
2.5210217320127413
>>> min(timeit.repeat(list_add))
2.0641671380144544
>>> min(timeit.repeat(deque_appendleft))
1.5863927800091915
>>> min(timeit.repeat(deque_extendleft))
0.5352169770048931

Le deque est beaucoup plus rapide. À mesure que les listes s'allongent, je m'attends à ce que les performances d'un deque soient encore meilleures. Si vous pouvez utiliser la fonction deque extendleft vous obtiendrez probablement les meilleures performances de cette façon.

58voto

Riliam Points 3

Si quelqu'un trouve cette question comme moi, voici mes tests de performance des méthodes proposées :

Python 2.7.8

In [1]: %timeit ([1]*1000000).insert(0, 0)
100 loops, best of 3: 4.62 ms per loop

In [2]: %timeit ([1]*1000000)[0:0] = [0]
100 loops, best of 3: 4.55 ms per loop

In [3]: %timeit [0] + [1]*1000000
100 loops, best of 3: 8.04 ms per loop

Comme vous pouvez le voir, insert et l'affectation de tranches sont presque deux fois plus rapides que l'addition explicite et leurs résultats sont très proches. Comme Raymond Hettinger noté insert est une option plus courante et, personnellement, je préfère cette façon de précéder la liste.

12voto

À mon avis, la manière la plus élégante et la plus idiomatique d'ajouter un élément ou une liste à une autre liste, en Python, est d'utiliser l'opérateur d'expansion * (également appelé opérateur de déballage),

# Initial list
l = [4, 5, 6]

# Modification
l = [1, 2, 3, *l]

Où la liste résultante après la modification est [1, 2, 3, 4, 5, 6]

J'aime aussi combiner simplement deux listes avec l'opérateur +, comme indiqué,

# Prepends [1, 2, 3] to l
l = [1, 2, 3] + l

# Prepends element 42 to l
l = [42] + l

Je n'aime pas l'autre approche courante, l.insert(0, value) car elle nécessite un nombre magique. De plus, insert() ne permet de faire précéder qu'un seul élément, mais l'approche ci-dessus a la même syntaxe pour faire précéder un élément unique ou plusieurs éléments.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X