pyplot - Was ist die idiomatische Syntax für eine kurze Python-Liste?




python plot numpy array (4)

list.append() ist die offensichtliche Wahl für das Hinzufügen am Ende einer Liste. Hier ist eine vernünftige Erklärung für die fehlende list.prepend() . Vorausgesetzt, meine Liste ist kurz und Leistungsbedenken sind vernachlässigbar, ist

list.insert(0, x)

oder

list[0:0] = [x]

idiomatisch?


Was ist die idiomatische Syntax für eine kurze Python-Liste?

Normalerweise möchten Sie nicht wiederholt einer Liste in Python vorangehen.

Wenn es kurz ist , und du machst es nicht oft ... dann ok.

list.insert

Die list.insert kann auf diese Weise verwendet werden.

list.insert(0, x)

Dies ist jedoch ineffizient, da in Python eine list ein Array von Zeigern ist und Python nun jeden Zeiger in der Liste nehmen und um eins nach unten verschieben muss, um den Zeiger auf Ihr Objekt im ersten Slot einzufügen effizient für eher kurze Listen, wie Sie fragen.

Wenn Sie einen Container benötigen, der effizient Elemente vorstellt, möchten Sie eine doppelt verknüpfte Liste. Python hat einen - es heißt deque .

deque.appendleft

Ein collections.deque hat viele Methoden einer Liste. list.sort ist eine Ausnahme, die deque definitiv nicht ganz Liskov für list substituierbar macht.

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

Die deque hat auch eine appendleft Methode (und auch popleft ). Die deque ist eine Double-Ended-Queue und eine doppelt verknüpfte Liste - egal wie lang sie ist, es dauert immer die gleiche Zeit, um etwas zu präjudizieren. In der großen O-Notation O (1) gegen die O (n) -Zeit für Listen. Hier ist die Verwendung:

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

deque.extendleft

Relevant ist auch die extendleft Methode der Deque, die iterativ vorangeht:

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

Beachten Sie, dass jedes Element einzeln vorangestellt wird, wodurch die Reihenfolge umgekehrt wird.

Leistung der list gegen deque

Zuerst haben wir mit einigen iterativen Voreinstellungen begonnen:

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

und Leistung:

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

Die Deque ist viel schneller. Wenn die Listen länger werden, würde ich erwarten, dass eine Deque noch besser wird. Wenn Sie die extendleft Deque verwenden können, extendleft Sie wahrscheinlich die beste Leistung.


Der erste ist sicherlich viel klarer und drückt die Absicht viel besser aus: Sie wollen nur ein einzelnes Element einfügen, nicht eine ganze Liste.


Wenn Sie den funktionalen Weg gehen können, ist das Folgende ziemlich klar

new_list = [x] + your_list

Natürlich haben Sie x in your_list eingefügt, sondern Sie haben eine neue Liste erstellt, in der x vorberechnet ist.


Wenn jemand diese Frage wie ich findet, hier sind meine Leistungstests der vorgeschlagenen Methoden:

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

Wie Sie sehen können, sind die insert und die Slice-Zuweisung fast doppelt so schnell wie beim expliziten Hinzufügen und liegen sehr nahe bei den Ergebnissen. Wie Raymond Hettinger angemerkt hat insert ist die insert gebräuchlicher und ich persönlich bevorzuge diesen Weg, um aufzulisten.





prepend