Criar lista de itens únicos repetidos N vezes

523

Quero criar uma série de listas, com comprimentos variados. Cada lista conterá o mesmo elemento e, repetidas nvezes (onde n= comprimento da lista).

Como crio as listas, sem usar uma compreensão de lista [e for number in xrange(n)]para cada lista?

chimeracoder
fonte

Respostas:

778

Você também pode escrever:

[e] * n

Você deve observar que, se e é, por exemplo, uma lista vazia, você obtém uma lista com n referências à mesma lista, e não n listas vazias independentes.

Teste de performance

À primeira vista, parece que a repetição é a maneira mais rápida de criar uma lista com n elementos idênticos:

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

Mas espere - não é um teste justo ...

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

A função itertools.repeatnão cria realmente a lista, apenas cria um objeto que pode ser usado para criar uma lista, se você desejar! Vamos tentar isso novamente, mas convertendo para uma lista:

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

Então, se você quiser uma lista, use [e] * n. Se você deseja gerar os elementos lentamente, use repeat.

Mark Byers
fonte
23
É altamente improvável que o desempenho da criação de uma lista com elementos idênticos seja um componente crítico do desempenho de um programa python.
Arthur
11
Como mencionado acima, se e for uma lista vazia, [[]] * npoderá produzir resultados inesperados. Para criar sub-listas vazias exclusivas , use-a para compreensão:[[] for i in range(0,n)]
Josiah Yoder 15/17
149
>>> [5] * 4
[5, 5, 5, 5]

Tenha cuidado quando o item que está sendo repetido for uma lista. A lista não será clonada: todos os elementos se referirão à mesma lista!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
gaefan
fonte
80

Criar lista de itens únicos repetidos n vezes em Python

Itens imutáveis

Para itens imutáveis, como None, bools, ints, floats, strings, tuplas ou frozensets, você pode fazer o seguinte:

[e] * 4

Observe que isso é melhor usado apenas com itens imutáveis ​​(cadeias de caracteres, tuplas, conjuntos de frozens) na lista, porque todos apontam para o mesmo item no mesmo local na memória. Uso isso frequentemente quando tenho que construir uma tabela com um esquema de todas as strings, para não precisar fornecer um mapeamento altamente redundante para um.

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

Itens mutáveis

Eu uso o Python há muito tempo e nunca vi um caso de uso em que faria isso acima com uma instância mutável. Em vez disso, para obter, digamos, uma lista vazia mutável, definir ou ditar, você deve fazer algo assim:

list_of_lists = [[] for _ in columns]

O sublinhado é simplesmente um nome de variável descartável nesse contexto.

Se você tiver apenas o número, seria:

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

A _não é realmente especial, mas o verificador de estilo ambiente de codificação provavelmente vai reclamar se você não pretende usar a variável e usar qualquer outro nome.


Advertências para o uso do método imutável com itens mutáveis:

Cuidado ao fazer isso com objetos mutáveis , quando você altera um deles, todos eles mudam porque são todos o mesmo objeto:

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

foo agora retorna:

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

Mas com objetos imutáveis, você pode fazê-lo funcionar porque altera a referência, não o objeto:

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

Mas, novamente, objetos mutáveis ​​não são bons para isso, porque as operações no local alteram o objeto, não a referência:

l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]
Aaron Hall
fonte
26

O Itertools tem uma função exatamente para isso:

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

É claro que itertoolsfornece um iterador em vez de uma lista. [e] * nfornece uma lista, mas, dependendo do que você fará com essas seqüências, a itertoolsvariante pode ser muito mais eficiente.

Jochen Ritzel
fonte
13

Como outros já apontaram, o uso do operador * para um objeto mutável duplica as referências; portanto, se você alterar um, altere todas. Se você deseja criar instâncias independentes de um objeto mutável, sua sintaxe xrange é a maneira mais Pythonic de fazer isso. Se você se incomodar com uma variável nomeada que nunca é usada, poderá usar a variável de sublinhado anônimo.

[e for _ in xrange(n)]
WP McNeill
fonte
10
[e] * n

Deveria trabalhar

Cientista maluco
fonte