Crea un elenco di singoli elementi ripetuti N volte


523

Voglio creare una serie di elenchi, tutti di diversa lunghezza. Ogni elenco conterrà lo stesso elemento e, ntempi ripetuti (dove n= lunghezza dell'elenco).

Come faccio a creare gli elenchi, senza utilizzare una comprensione degli elenchi [e for number in xrange(n)]per ciascun elenco?

Risposte:


778

Puoi anche scrivere:

[e] * n

Si noti che se e, ad esempio, è un elenco vuoto, si ottiene un elenco con n riferimenti allo stesso elenco, non n elenchi vuoti indipendenti.

Test delle prestazioni

A prima vista sembra che la ripetizione sia il modo più veloce per creare un elenco con n elementi identici:

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

Ma aspetta - non è un test giusto ...

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

La funzione in itertools.repeatrealtà non crea l'elenco, ma crea semplicemente un oggetto che può essere usato per creare un elenco se lo desideri! Proviamo di nuovo, ma convertendo in un elenco:

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

Quindi, se si desidera un elenco, utilizzare [e] * n. Se vuoi generare pigramente gli elementi, usa repeat.


23
È altamente improbabile che le prestazioni della creazione di un elenco con elementi identici siano un componente critico delle prestazioni di un programma Python.
Arthur,

11
Come accennato in precedenza, se e è un elenco vuoto [[]] * npuò produrre risultati imprevisti. Per creare sotto-elenchi vuoti unici , utilizzare per la comprensione:[[] for i in range(0,n)]
Josiah Yoder il

149
>>> [5] * 4
[5, 5, 5, 5]

Fare attenzione quando l'elemento che si ripete è un elenco. L'elenco non verrà clonato: tutti gli elementi faranno riferimento allo stesso elenco!

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

80

Crea un elenco di singoli elementi ripetuti n volte in Python

Oggetti immutabili

Per oggetti immutabili, come Nessuno, bool, ints, float, stringhe, tuple o frozenset, puoi farlo in questo modo:

[e] * 4

Nota che questo è meglio usato solo con oggetti immutabili (stringhe, tuple, frozenset,) nell'elenco, perché puntano tutti allo stesso oggetto nello stesso posto in memoria. Lo uso frequentemente quando devo costruire una tabella con uno schema di tutte le stringhe, in modo da non doverne assegnare uno altamente ridondante a una mappatura.

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

Oggetti mutabili

Ho usato Python per molto tempo e non ho mai visto un caso d'uso in cui farei quanto sopra con un'istanza mutabile. Invece, per ottenere, diciamo, una lista vuota mutevole, impostata o dettata, dovresti fare qualcosa del genere:

list_of_lists = [[] for _ in columns]

Il carattere di sottolineatura è semplicemente un nome variabile usa e getta in questo contesto.

Se hai solo il numero, sarebbe:

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

Non _è davvero speciale, ma il tuo verificatore di stili di ambiente di codifica probabilmente si lamenterà se non intendi utilizzare la variabile e utilizzare un altro nome.


Avvertenze per l'utilizzo del metodo immutabile con oggetti mutabili:

Fai attenzione con oggetti mutabili , quando ne cambi uno, cambiano tutti perché sono tutti lo stesso oggetto:

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

foo ora ritorna:

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

Ma con oggetti immutabili, puoi farlo funzionare perché cambi il riferimento, non l'oggetto:

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

Ma ancora una volta, gli oggetti mutabili non vanno bene per questo, perché le operazioni sul posto cambiano l'oggetto, non il riferimento:

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 ha una funzione proprio per questo:

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

Ovviamente itertoolsti dà un iteratore invece di un elenco. [e] * nti dà un elenco, ma, a seconda di cosa farai con quelle sequenze, la itertoolsvariante può essere molto più efficiente.


13

Come altri hanno sottolineato, l'uso dell'operatore * per un oggetto mutabile duplica i riferimenti, quindi se ne cambi uno, li cambi tutti. Se vuoi creare istanze indipendenti di un oggetto mutabile, la tua sintassi xrange è il modo più Pythonic per farlo. Se sei infastidito dalla presenza di una variabile con nome che non viene mai utilizzata, puoi utilizzare la variabile di sottolineatura anonima.

[e for _ in xrange(n)]

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.