list.append()附加到列表的末尾。这解释了list.prepend()不存在的原因,因为考虑到大型列表的性能。对于一个短列表,我如何预先一个值?


当前回答

一个简短的python列表的前缀的惯用语法是什么?

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

如果清单很短,而且你做的不多……然后点击ok。

list.insert

列表中。Insert可以这样使用。

list.insert(0, x)

但这是低效的,因为在Python中,列表是一个指针数组,Python现在必须取列表中的每个指针并将其向下移动1,以将指针插入到第一个槽中的对象,所以这实际上只对相当短的列表有效。

这是CPython源代码中的一个代码片段,在这里实现了这个功能——正如你所看到的,我们从数组的末尾开始,每次插入都将所有内容下移1:

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

如果你想要一个容器/列表,它可以有效地预挂元素,你需要一个链表。Python有一个双链表,它可以快速插入开头和结尾——它被称为deque。

deque.appendleft

collections.deque具有列表的许多方法。列表。sort是个例外,这使得deque绝对不能完全用Liskov方法代替list。

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

deque还有一个appendleft方法(以及popleft方法)。deque是一个双端队列和一个双链表——无论长度如何,它总是花费相同的时间来预前缀一些东西。在大O符号中,O(1) vs 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'])

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

list相对于deque的性能

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

import timeit
from collections import deque


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

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

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

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

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

还有一个用于分析的函数,这样我们就可以公平地比较一系列用法中的所有操作:

def compare_prepends(n, runs_per_trial):
    results = {}
    for function in (
        list_insert_0, list_slice_insert,
        list_add, deque_appendleft, deque_extendleft,
        ):
        shortest_time = min(timeit.repeat(
            lambda: function(n), number=runs_per_trial))
        results[function.__name__] = shortest_time
    ranked_methods = sorted(results.items(), key=lambda kv: kv[1])
    for name, duration in ranked_methods:
        print(f'{name} took {duration} seconds')

性能(调整每次试验的运行次数,以弥补更多prepends的较长运行时间-默认情况下重复做三次试验):

compare_prepends(20, 1_000_000)
compare_prepends(100, 100_000)
compare_prepends(500, 100_000)
compare_prepends(2500, 10_000)
>>> compare_prepends(20, 1_000_000)
deque_extendleft took 0.6490256823599339 seconds
deque_appendleft took 1.4702797569334507 seconds
list_insert_0 took 1.9417422469705343 seconds
list_add took 2.7092894352972507 seconds
list_slice_insert took 3.1809083241969347 seconds
>>> compare_prepends(100, 100_000)
deque_extendleft took 0.1177942156791687 seconds
deque_appendleft took 0.5385235995054245 seconds
list_insert_0 took 0.9471780974417925 seconds
list_slice_insert took 1.4850486349314451 seconds
list_add took 2.1660344172269106 seconds
>>> compare_prepends(500, 100_000)
deque_extendleft took 0.7309095915406942 seconds
deque_appendleft took 2.895373275503516 seconds
list_slice_insert took 8.782583676278591 seconds
list_insert_0 took 8.931685039773583 seconds
list_add took 30.113558700308204 seconds
>>> compare_prepends(2500, 10_000)
deque_extendleft took 0.4839253816753626 seconds
deque_appendleft took 1.5615574326366186 seconds
list_slice_insert took 6.712615916505456 seconds
list_insert_0 took 13.894083382561803 seconds
list_add took 72.1727528590709 seconds

deque要快得多。当列表变长时,deque执行得更好。如果你可以使用deque的extendleft,你可能会得到最好的性能。

如果您必须使用列表,请记住,对于小列表,列表。插入工作更快,但对于较大的列表,使用切片符号进行插入会更快。

不要在列表前加前缀

清单是用来附加的,而不是前面的。如果你遇到这种情况,这种前置会损害你的代码的性能,要么切换到deque,或者,如果你可以逆转你的语义并达到同样的目标,逆转你的列表,而不是追加。

一般情况下,避免在内置的Python列表对象前加上前缀。

其他回答

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

无论何时看到它,都应该考虑使用collections.deque而不是列表。deque的前置操作在常数时间内运行。列表的前置操作以线性时间运行。

我们来看4种方法

使用insert ()

>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l.insert(0, 5)
>>> l
[5, 0, 1, 2, 3, 4]
>>> 

使用[]和+

>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l = [5] + l
>>> l
[5, 0, 1, 2, 3, 4]
>>> 

使用切片

>>> 
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l[:0] = [5]
>>> l
[5, 0, 1, 2, 3, 4]
>>> 

使用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]
>>> 

这将创建一个带x的新列表,而不是修改现有的列表:

new_list = [x] + old_list

一个简短的python列表的前缀的惯用语法是什么?

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

如果清单很短,而且你做的不多……然后点击ok。

list.insert

列表中。Insert可以这样使用。

list.insert(0, x)

但这是低效的,因为在Python中,列表是一个指针数组,Python现在必须取列表中的每个指针并将其向下移动1,以将指针插入到第一个槽中的对象,所以这实际上只对相当短的列表有效。

这是CPython源代码中的一个代码片段,在这里实现了这个功能——正如你所看到的,我们从数组的末尾开始,每次插入都将所有内容下移1:

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

如果你想要一个容器/列表,它可以有效地预挂元素,你需要一个链表。Python有一个双链表,它可以快速插入开头和结尾——它被称为deque。

deque.appendleft

collections.deque具有列表的许多方法。列表。sort是个例外,这使得deque绝对不能完全用Liskov方法代替list。

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

deque还有一个appendleft方法(以及popleft方法)。deque是一个双端队列和一个双链表——无论长度如何,它总是花费相同的时间来预前缀一些东西。在大O符号中,O(1) vs 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'])

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

list相对于deque的性能

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

import timeit
from collections import deque


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

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

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

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

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

还有一个用于分析的函数,这样我们就可以公平地比较一系列用法中的所有操作:

def compare_prepends(n, runs_per_trial):
    results = {}
    for function in (
        list_insert_0, list_slice_insert,
        list_add, deque_appendleft, deque_extendleft,
        ):
        shortest_time = min(timeit.repeat(
            lambda: function(n), number=runs_per_trial))
        results[function.__name__] = shortest_time
    ranked_methods = sorted(results.items(), key=lambda kv: kv[1])
    for name, duration in ranked_methods:
        print(f'{name} took {duration} seconds')

性能(调整每次试验的运行次数,以弥补更多prepends的较长运行时间-默认情况下重复做三次试验):

compare_prepends(20, 1_000_000)
compare_prepends(100, 100_000)
compare_prepends(500, 100_000)
compare_prepends(2500, 10_000)
>>> compare_prepends(20, 1_000_000)
deque_extendleft took 0.6490256823599339 seconds
deque_appendleft took 1.4702797569334507 seconds
list_insert_0 took 1.9417422469705343 seconds
list_add took 2.7092894352972507 seconds
list_slice_insert took 3.1809083241969347 seconds
>>> compare_prepends(100, 100_000)
deque_extendleft took 0.1177942156791687 seconds
deque_appendleft took 0.5385235995054245 seconds
list_insert_0 took 0.9471780974417925 seconds
list_slice_insert took 1.4850486349314451 seconds
list_add took 2.1660344172269106 seconds
>>> compare_prepends(500, 100_000)
deque_extendleft took 0.7309095915406942 seconds
deque_appendleft took 2.895373275503516 seconds
list_slice_insert took 8.782583676278591 seconds
list_insert_0 took 8.931685039773583 seconds
list_add took 30.113558700308204 seconds
>>> compare_prepends(2500, 10_000)
deque_extendleft took 0.4839253816753626 seconds
deque_appendleft took 1.5615574326366186 seconds
list_slice_insert took 6.712615916505456 seconds
list_insert_0 took 13.894083382561803 seconds
list_add took 72.1727528590709 seconds

deque要快得多。当列表变长时,deque执行得更好。如果你可以使用deque的extendleft,你可能会得到最好的性能。

如果您必须使用列表,请记住,对于小列表,列表。插入工作更快,但对于较大的列表,使用切片符号进行插入会更快。

不要在列表前加前缀

清单是用来附加的,而不是前面的。如果你遇到这种情况,这种前置会损害你的代码的性能,要么切换到deque,或者,如果你可以逆转你的语义并达到同样的目标,逆转你的列表,而不是追加。

一般情况下,避免在内置的Python列表对象前加上前缀。

我会在python >= 3.0中做一些非常快的事情

list=[0,*list]

这可能不是最有效的方法,但在我看来这是最python化的方法。