在一个简短的python列表前加上什么惯用语法?

2024-03-28 21:32:26 发布

您现在位置:Python中文网/ 问答频道 /正文

list.append()是添加到列表末尾的明显选择。这里有一个reasonable explanation用于查找丢失的list.prepend()。假设我的列表很短,性能问题可以忽略不计,那么

list.insert(0, x)

或者

list[0:0] = [x]

习惯用语?


Tags: 列表性能listinsertprepend末尾explanationappend
3条回答

如果你能走功能性的道路,下面就很清楚了

new_list = [x] + your_list

当然,您并没有将x插入到your_list中,而是创建了一个预先添加了x的新列表。

What's the idiomatic syntax for prepending to a short python list?

在Python中,您通常不希望重复地在列表前面加上前缀。

如果它是短的,而你做的不多。。。那好吧。

list.insert

可以这样使用list.insert

list.insert(0, x)

但这是低效的,因为在Python中,list是一个指针数组,Python现在必须获取列表中的每个指针,并将其向下移动一个,以便在第一个槽中插入指向对象的指针,所以这实际上只对较短的列表有效,正如您所要求的那样。

这里有一个代码片段from the CPython source在这里实现了这一点-如您所见,我们从数组的末尾开始,每次插入时将所有内容向下移动一个:

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

如果希望容器/列表在元素前加有效的前缀,则需要链接列表。Python有一个双链接列表,它可以快速地插入开头和结尾,称为deque

deque.appendleft

collections.deque有许多列表方法。list.sort是一个例外,使得deque最终不能完全替代list的Liskov。

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

deque还有一个appendleft方法(以及popleft)。deque是一个双端队列和一个双链接列表-无论长度如何,预处理某事总是需要相同的时间。在大O表示法中,O(1)与列表的O(n)时间之比。用法如下:

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

deque.extendleft

与此相关的还有deque的extendleft方法,该方法迭代地预先:

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

请注意,每个元素将一次添加一个前缀,从而有效地颠倒它们的顺序。

listdeque

的性能

首先,我们设置一些迭代的前置:

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

以及性能:

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

德克要快得多。随着名单越来越长,我预计德克会表现得更好。如果您可以使用deque的extendleft,那么您可能会获得最好的性能。

最常见的是s.insert(0, x)形式。

不过,无论何时看到它,都可能是考虑使用collections.deque而不是使用列表的时候了。

相关问题 更多 >