Создание списка из одного элемента, повторяющегося 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]
Будьте осторожны, когда повторяющийся элемент является списком. Список не будет клонирован: все элементы будут ссылаться на один и тот же список!
Создание списка из одного элемента, повторяющегося 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 inrange(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 _ inrange(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([])]
Но опять же, изменяемые объекты для этого не подходят, потому что операции на месте изменяют объект, а не ссылку:
Конечно, itertools предоставляет вам итератор вместо списка. [e] * n предоставляет вам список, но, в зависимости от того, что вы будете делать с этими последовательностями, itertools вариант может быть намного более эффективным.