前缀为短python列表的惯用语法是什么?

时间:2011-12-16 17:30:01

标签: python list prepend

list.append()是添加到列表末尾的明显选择。这是丢失的list.prepend()的{​​{3}}。假设我的列表很短并且性能问题可以忽略不计,那么

list.insert(0, x)

list[0:0] = [x]

惯用?

7 个答案:

答案 0 :(得分:652)

s.insert(0, x)表格是最常见的。

无论何时看到它,都可以考虑使用collections.deque代替列表。

答案 1 :(得分:218)

如果你可以采用功能方式,以下内容非常清楚

new_list = [x] + your_list

当然,您尚未将x插入your_list,而是已创建了一个新的列表x已预先准备好。

答案 2 :(得分:66)

  

前缀为短python列表的惯用语法是什么?

您通常不希望重复使用Python中的列表。

如果它是 ,而你没有做太多......那就好了。

list.insert

list.insert可以这种方式使用。

list.insert(0, x)

但是效率很低,因为在Python中,list是一个指针数组,Python现在必须将列表中的每个指针都向下移动一个,以便在第一个指针中插入指针。插槽,所以这对于相当短的列表来说真的很有效,就像你问的那样。

如果你想要一个能够在前置元素上有效的容器,你需要一个双向链表。 Python有一个 - 它被称为deque

deque.appendleft

collections.deque有许多列表方法。 list.sort是一个例外,使deque明确地不完全Liskov可替代list

>>> 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能够表现得更好。如果你可以使用deque的extendleft,那么你可能会获得最好的表现。

答案 3 :(得分:55)

如果有人发现像我这样的问题,这是我对提议方法的性能测试:

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

正如您所看到的,insert和切片分配几乎是显式添加的两倍,并且结果非常接近。由于Raymond Hettinger注意到insert是更常见的选项,我个人更喜欢这种方式来预先列出。

答案 4 :(得分:4)

第一个肯定更清晰,更好地表达了意图:你只想插入一个元素,而不是整个列表。

答案 5 :(得分:1)

我认为,在Python中,将元素或列表添加到另一个列表的最优雅,最惯用的方式是使用扩展运算符*(也称为解包运算符),

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

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

修改后的结果列表为[1, 2, 3, 4, 5, 6]

我还喜欢简单地将两个列表与运算符+组合在一起,如图所示,

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

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

我不喜欢另一种常见的方法l.insert(0, value),因为它需要一个幻数。此外,insert()仅允许添加一个元素,但是上述方法具有添加一个或多个元素的相同语法。

答案 6 :(得分:0)

让我们来看看 4 种方法

  1. 使用 insert()
>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l.insert(0, 5)
>>> l
[5, 0, 1, 2, 3, 4]
>>> 
  1. 使用 [] 和 +
>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l = [5] + l
>>> l
[5, 0, 1, 2, 3, 4]
>>> 
  1. 使用切片
>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l[:0] = [5]
>>> l
[5, 0, 1, 2, 3, 4]
>>> 
  1. 使用 collections.deque.appendleft()
>>> 
>>> from collections import deque
>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l = deque(l)
>>> l.appendleft(5)
>>> l = list(l)
>>> l
[5, 0, 1, 2, 3, 4]
>>>