Utwórz listę pojedynczego elementu powtarzanego N razy

522

Chcę stworzyć serię list o różnej długości. Każda lista będzie zawierać ten sam element e, powtarzane nrazy (gdzie n= długość listy).

Jak utworzyć listy bez korzystania ze zrozumienia listy [e for number in xrange(n)]dla każdej listy?

chimerakoder
źródło

Odpowiedzi:

777

Możesz także napisać:

[e] * n

Należy zauważyć, że jeśli e jest na przykład pustą listą, otrzymujesz listę z n odniesieniami do tej samej listy, a nie n niezależnymi pustymi listami.

Test wydajności

Na pierwszy rzut oka wydaje się, że powtórzenie jest najszybszym sposobem na utworzenie listy zawierającej n identycznych elementów:

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

Ale czekaj - to nie jest uczciwy test ...

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

Ta funkcja itertools.repeatnie tworzy listy, po prostu tworzy obiekt, którego można użyć do utworzenia listy, jeśli chcesz! Spróbujmy jeszcze raz, ale przechodząc do listy:

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

Więc jeśli chcesz listę, użyj [e] * n. Jeśli chcesz generować elementy leniwie, użyj repeat.

Mark Byers
źródło
23
Jest bardzo mało prawdopodobne, aby wydajność tworzenia listy z identycznymi elementami była kluczowym składnikiem wydajności programu python.
Arthur
11
Jak wspomniano powyżej, jeśli e jest pustą listą, [[]] * nmoże ona dać nieoczekiwane wyniki. Aby utworzyć unikalne puste listy podrzędne , skorzystaj ze zrozumienia:[[] for i in range(0,n)]
Josiah Yoder
149
>>> [5] * 4
[5, 5, 5, 5]

Uważaj, gdy powtarzany element jest listą. Lista nie zostanie sklonowana: wszystkie elementy będą odnosić się do tej samej listy!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
gaefan
źródło
80

Utwórz listę powtarzanych pojedynczych elementów n razy w Pythonie

Niezmienne przedmioty

W przypadku niezmiennych przedmiotów, takich jak None, bools, ints, floats, strings, tuples lub frozensets, możesz to zrobić w następujący sposób:

[e] * 4

Zauważ, że najlepiej tego używać tylko z niezmiennymi elementami (ciągami, krotkami, frozensetami) na liście, ponieważ wszystkie wskazują na ten sam element w tym samym miejscu w pamięci. Używam tego często, gdy muszę zbudować tabelę ze schematem wszystkich łańcuchów, aby nie musiałem nadawać bardzo redundantnego mapowania jeden do jednego.

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

Przedmioty zmienne

Używam Pythona od dłuższego czasu i nigdy nie widziałem przypadku użycia, w którym zrobiłbym powyższe z modyfikowalną instancją. Zamiast tego, aby uzyskać, powiedzmy, zmienną pustą listę, ustawić lub dyktować, powinieneś zrobić coś takiego:

list_of_lists = [[] for _ in columns]

Podkreślenie to po prostu zmienna nazwa zmiennej w tym kontekście.

Jeśli masz tylko numer, byłoby to:

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

Nie _jest to tak naprawdę wyjątkowe, ale sprawdzanie stylu środowiska kodowania prawdopodobnie narzeka, jeśli nie zamierzasz używać zmiennej i używać żadnej innej nazwy.


Ostrzeżenia dotyczące stosowania niezmiennej metody ze zmiennymi przedmiotami:

Strzeż się robienia tego ze zmiennymi obiektami , kiedy zmienisz jeden z nich, wszystkie się zmieniają, ponieważ wszystkie są tym samym obiektem:

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

foo teraz zwraca:

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

Ale w przypadku obiektów niezmiennych możesz sprawić, że będzie działać, ponieważ zmienisz odwołanie, a nie obiekt:

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

Ale znowu, zmienne obiekty nie nadają się do tego, ponieważ operacje w miejscu zmieniają obiekt, a nie odwołanie:

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
źródło
26

Itertools ma właśnie taką funkcję:

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

Oczywiście itertoolsdaje iterator zamiast listy. [e] * ndaje listę, ale w zależności od tego, co zrobisz z tymi sekwencjami, itertoolswariant może być znacznie wydajniejszy.

Jochen Ritzel
źródło
13

Jak zauważyli inni, użycie operatora * dla obiektu zmiennego powiela odniesienia, więc jeśli zmienisz jeden, zmień je wszystkie. Jeśli chcesz utworzyć niezależne instancje obiektu zmiennego, twoja składnia xrange jest najbardziej Pythońskim sposobem na zrobienie tego. Jeśli przeszkadza ci, że zmienna nazwana, która nigdy nie jest używana, możesz użyć anonimowej zmiennej podkreślenia.

[e for _ in xrange(n)]
WP McNeill
źródło
10
[e] * n

powinno działać

Szalony naukowiec
źródło