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


523

Я хочу створити ряд списків, різної довжини. Кожен список буде містити один і той же елемент e, повторений nраз (де n= довжина списку).

Як створити списки, не використовуючи розуміння списку [e for number in xrange(n)]для кожного списку?

Відповіді:


778

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

[e] * n

Слід зазначити, що якщо e, наприклад, порожній список, ви отримуєте список з n посиланнями на той самий список, а не 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)]
Йосія Йодер

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

80

Створіть список одноразових повторень n разів у Python

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

Для незмінних елементів, таких як None, bools, ints, floats, strings, кортежі або frozensets, ви можете це зробити так:

[e] * 4

Зауважте, що це найкраще використовувати лише із змінних елементів (рядків, кортежів, фрозенсетів,) у списку, оскільки всі вони вказують на один і той же елемент у тому самому місці пам’яті. Я часто використовую це, коли мені доводиться будувати таблицю зі схемою всіх рядків, так що мені не потрібно давати дуже надмірне відображення на одне.

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

Змінні предмети

Я вже давно використовую Python, і я ніколи не бачив випадків використання, де я робив би вищезазначене із змінним екземпляром. Натомість, щоб отримати, скажімо, порожній список, набір або диктування, що змінюється, вам слід зробити щось подібне:

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)]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.