Какой идиоматический синтаксис для добавления в короткий список питонов?

list.append() является очевидным выбором для добавления в конец списка. Вот разумное объяснение пропавшего без вести list.prepend(), Если предположить, что мой список короткий и проблемы с производительностью незначительны,

list.insert(0, x)

или же

list[0:0] = [x]

идиоматическое?

9 ответов

Решение

s.insert(0, x) форма является наиболее распространенным.

Когда бы вы ни увидели это, возможно, пришло время рассмотреть возможность использования collection.deque вместо списка.

Если вы можете пойти функциональным путем, следующее довольно ясно

new_list = [x] + your_list

Конечно, вы не вставили x в your_listскорее вы создали новый список с x приготовился к этому.

Какой идиоматический синтаксис для добавления в короткий список питонов?

Обычно вы не хотите повторяться перед списком в Python.

Если оно короткое, и ты не часто этим занимаешься... тогда хорошо.

list.insert

list.insert можно использовать таким образом.

list.insert(0, x)

Но это неэффективно, потому что в Python, list является массивом указателей, и теперь Python должен взять каждый указатель в списке и переместить его вниз на единицу, чтобы вставить указатель на ваш объект в первом слоте, так что это действительно эффективно только для довольно коротких списков, как вы просите.

Если вам нужен контейнер, эффективный для добавления элементов, вам нужен список с двумя связями. У Python есть один - он называется deque,

deque.appendleft

collections.deque имеет много методов списка. list.sort исключение, делающее deque окончательно не полностью заменяемый Лисковым 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's 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():
    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 будет работать еще лучше. Если вы можете использовать Deque's extendleft вы, вероятно, получите лучшую производительность таким образом.

Если кто-то найдет этот вопрос, как я, вот мои тесты производительности предлагаемых методов:

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 и назначение среза почти в два раза быстрее, чем явное добавление, и очень близки по результатам. Как отметил Раймонд Хеттингер insert это более распространенный вариант, и я, лично, предпочитаю этот способ, чтобы добавить в список.

На мой взгляд, наиболее элегантный и идиоматический способ добавления элемента или списка в другой список в 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() позволяет добавлять только один элемент, однако описанный выше подход имеет тот же синтаксис для добавления одного или нескольких элементов в начале.

Первый, безусловно, намного понятнее и выражает намерение гораздо лучше: вы хотите вставить только один элемент, а не целый список.

Давайте рассмотрим 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]
>>> 

Я бы сделал что-то довольно быстро в python >= 3.0

      list=[0,*list]

Возможно, это не самый эффективный способ, но, на мой взгляд, самый Pythonic.

Для небольшого списка вы можете использовать метод Insert(), чтобы добавить значение в список:

      my_list = [2, 3, 4]
my_list.insert(0, 1)

Однако для больших списков может быть более эффективно использовать двухстороннюю очередь вместо списка:

      from collections import deque

my_list = deque([2, 3, 4])
my_list.appendleft(1)

Деки — это структура данных, которая поддерживает эффективные операции добавления и добавления и обычно работает быстрее, чем списки для больших структур данных.

Другие вопросы по тегам