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

523

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

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

chimeracoder
источник

Ответы:

778

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

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

Марк Байерс
источник
23
Маловероятно, что производительность создания списка с идентичными элементами будет критическим компонентом производительности программы на Python.
Артур
11
Как упомянуто выше, если e - пустой список, [[]] * nможет привести к неожиданным результатам. Чтобы создать уникальные пустые [[] for i in range(0,n)]
Josiah Yoder
149
>>> [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]]
gaefan
источник
80

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

Неизменные предметы

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

[e] * 4

Обратите внимание, что это лучше всего использовать только с неизменяемыми элементами (строками, кортежами, frozensets,) в списке, потому что все они указывают на один и тот же элемент в одном и том же месте в памяти. Я использую это часто, когда мне нужно построить таблицу со схемой из всех строк, чтобы мне не приходилось давать сильно избыточное сопоставление один к одному.

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

Изменчивые предметы

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

list_of_lists = [[] for _ in columns]

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

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

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'])]
Аарон Холл
источник
26

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

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

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

Йохен Ритцель
источник
13

Как уже отмечали другие, использование оператора * для изменяемого объекта дублирует ссылки, поэтому, если вы измените один, вы измените их все. Если вы хотите создать независимые экземпляры изменяемого объекта, ваш синтаксис xrange - самый питонский способ сделать это. Если вас беспокоит наличие именованной переменной, которая никогда не используется, вы можете использовать анонимную переменную подчеркивания.

[e for _ in xrange(n)]
WP McNeill
источник
10
[e] * n

должно сработать

Злой ученый
источник