Вопрос-Ответ

Create list of single item repeated N times

Создание списка из одного элемента, повторяющегося N раз

Я хочу создать серию списков разной длины. Каждый список будет содержать один и тот же элемент, e повторяющийся n раз (где n = длина списка).

Как мне создавать списки, не используя понимание списка [e for number in xrange(n)] для каждого списка?

Переведено автоматически
Ответ 1

Вы также можете написать:

[e] * n

Следует отметить, что если e, например, является пустым списком, вы получаете список с n ссылками на один и тот же список, а не с n независимыми пустыми списками.

Тестирование производительности

На первый взгляд кажется, что repeat - это самый быстрый способ создать список из n идентичных элементов:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

Но подождите - это не честный тест...

>>> itertools.repeat(0, 10)
repeat(0, 10) # Not a list!!!

Функция itertools.repeat на самом деле не создает список, она просто создает объект, который при желании можно использовать для создания списка! Давайте попробуем это снова, но преобразовав в список:

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

Итак, если вам нужен список, используйте [e] * n. Если вы хотите лениво генерировать элементы, используйте repeat.

Ответ 2
>>> [5] * 4
[5, 5, 5, 5]

Будьте осторожны, когда повторяющийся элемент является списком. Список не будет клонирован: все элементы будут ссылаться на один и тот же список!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
Ответ 3

Создание списка из одного элемента, повторяющегося n раз в Python


В зависимости от вашего варианта использования вы хотите использовать разные методы с разной семантикой.

Умножьте список на неизменяемые элементы

Для неизменяемых элементов, таких как None, bools, ints, floats, strings, tuples или frozensets, вы можете сделать это следующим образом:

[e] * 4

Например:

>>> [None] * 4
[None, None, None, None]

Обратите внимание, что обычно это используется только с неизменяемыми элементами (строками, кортежами, замороженными наборами и т.д.) В списке, потому что все они указывают на один и тот же элемент в одном и том же месте в памяти.

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

schema = ['string'] * len(columns)

Умножьте список там, где мы хотим, чтобы тот же элемент с изменяемым состоянием повторялся

При умножении списка мы получаем одни и те же элементы снова и снова. Необходимость в этом возникает нечасто:

[iter(iterable)] * 4

Иногда это используется для отображения итеративного элемента в список списков:

>>> iterable = range(12)
>>> a_list = [iter(iterable)] * 4
>>> [[next(l) for l in a_list] for i in range(3)] # uninteresting usage
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]

Мы можем видеть, что a_list содержит один и тот же итератор диапазона четыре раза:

>>> from pprint import pprint
>>> pprint(a_list)
[<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>]

Изменяемые элементы

Я использую Python уже давно, и я видел очень мало вариантов использования, когда я делал бы описанное выше с изменяемыми объектами.

Вместо этого, чтобы повторить, скажем, изменяемый пустой список, set или dict, вы должны сделать что-то вроде этого:

list_of_lists = [[] for _ in iterator_of_needed_length]

Подчеркивание - это просто одноразовое имя переменной в данном контексте.

Если у вас есть только номер, это будет:

list_of_lists = [[] for _ in range(4)]

В _ качестве одноразового имени на самом деле нет ничего особенного, но статический анализатор кода, вероятно, пожалуется, если вы не собираетесь использовать переменную и используете любое другое имя.


Предостережения при использовании метода умножения с изменяемыми элементами:

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

foo = [[]] * 4
foo[0].append('x')

foo теперь возвращает:

[['x'], ['x'], ['x'], ['x']]

Но с неизменяемыми объектами вы можете заставить это работать, потому что вы меняете ссылку, а не объект:

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

Но опять же, изменяемые объекты для этого не подходят, потому что операции на месте изменяют объект, а не ссылку:

l = [set()] * 4
>>> l[0] |= set('abc')
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]
Ответ 4

В Itertools есть функция именно для этого:

import itertools
it = itertools.repeat(e,n)

Конечно, itertools предоставляет вам итератор вместо списка. [e] * n предоставляет вам список, но, в зависимости от того, что вы будете делать с этими последовательностями, itertools вариант может быть намного более эффективным.

python