web-dev-qa-db-fra.com

Quelle est la syntaxe idiomatique à utiliser pour ajouter une liste courte python?

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

list.insert(0, x)

ou

list[0:0] = [x]

idiomatique?

465
hurrymaplelad

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

Cependant, chaque fois que vous le voyez, il est temps d’envisager d’utiliser un collections.deque au lieu d’une liste.

671
Raymond Hettinger

Si vous pouvez aller de manière fonctionnelle, ce qui suit est assez clair

new_list = [x] + your_list

Bien sûr, vous n'avez pas inséré x dans your_list, vous avez plutôt créé une nouvelle liste avec x pré-programmée.

224
Nil Geisweiller

Quelle est la syntaxe idiomatique à utiliser pour ajouter une liste courte python?

En règle générale, vous ne voulez pas ajouter de liste répétitive à une liste en Python.

Si c'est court , et que vous ne le faites pas beaucoup ... alors ok.

list.insert

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

list.insert(0, x)

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

Voici un extrait de la source CPython où cela est implémenté - et comme vous pouvez le constater, nous commençons à la fin du tableau et déplaçons le tout d'un vers le bas pour chaque insertion:

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

Si vous voulez un conteneur/une liste qui soit efficace pour ajouter des éléments, vous voulez une liste chaînée. Python a une liste doublement chaînée, qui peut être insérée au début et à la fin rapidement - elle s'appelle un deque.

deque.appendleft

Un collections.deque a beaucoup des méthodes d'une liste. list.sort est une exception, rendant deque définitivement pas entièrement Liskov substituable à list.

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

La deque possède également une méthode appendleft (ainsi que popleft). La deque est une file d'attente à double extrémité et une liste à double liaison - quelle que soit leur longueur, il faut toujours le même temps pour préparer quelque chose. En grosse notation O, O(1) par rapport à la durée 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

La méthode extendleft de deque, également précieuse par itération:

>>> 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 à un, inversant ainsi leur ordre.

Performance de list versus deque

Premièrement, nous installons avec un peu de prépresse itérative:

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 performance:

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

La deque est beaucoup plus rapide. Au fur et à mesure que les listes s'allongent, je m'attendrais à ce qu'une deque se comporte encore mieux. Si vous pouvez utiliser extendleft de deque, vous obtiendrez probablement la meilleure performance de cette façon.

73
Aaron Hall

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 constater, insert et l’attribution de tranches sont presque deux fois plus rapides que l’ajout explicite et sont très proches dans les résultats. Comme Raymond Hettinger noté insert est une option plus commune et je préfère personnellement cette façon de préfixer à la liste.

56

Le premier est certainement beaucoup plus clair et exprime bien mieux l'intention: vous voulez seulement insérer un seul élément, pas une liste complète.

2
Paul Manta