Créer une liste d'éléments uniques répétés N fois

523

Je veux créer une série de listes, toutes de longueurs variables. Chaque liste contiendra le même élément e, répété nfois (où n= longueur de la liste).

Comment créer les listes, sans utiliser une compréhension de liste [e for number in xrange(n)]pour chaque liste?

chiméracodeur
la source

Réponses:

778

Vous pouvez également écrire:

[e] * n

Vous devez noter que si e est par exemple une liste vide, vous obtenez une liste avec n références à la même liste, pas n listes vides indépendantes.

Test de performance

À première vue, il semble que la répétition soit le moyen le plus rapide de créer une liste avec n éléments identiques:

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

Mais attendez - ce n'est pas un test juste ...

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

La fonction itertools.repeatne crée pas réellement la liste, elle crée juste un objet qui peut être utilisé pour créer une liste si vous le souhaitez! Essayons à nouveau, mais convertissons-les en liste:

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

Donc, si vous voulez une liste, utilisez [e] * n. Si vous souhaitez générer les éléments paresseusement, utilisez repeat.

Mark Byers
la source
23
Il est hautement improbable que les performances de création d'une liste avec des éléments identiques soient un composant critique des performances d'un programme python.
Arthur
11
Comme mentionné ci-dessus, si e est une liste vide, cela [[]] * npeut produire des résultats inattendus. Pour créer des sous-listes vides uniques , utilisez pour la compréhension:[[] for i in range(0,n)]
Josiah Yoder
149
>>> [5] * 4
[5, 5, 5, 5]

Soyez prudent lorsque l'élément répété est une liste. La liste ne sera pas clonée: tous les éléments feront référence à la même liste!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
Gaefan
la source
80

Créer une liste d'éléments uniques répétés n fois en Python

Éléments immuables

Pour les éléments immuables, comme Aucun, bools, ints, flotteurs, cordes, tuples ou frozensets, vous pouvez le faire comme ceci:

[e] * 4

Notez qu'il est préférable de l'utiliser uniquement avec des éléments immuables (chaînes, tuples, frozensets,) dans la liste, car ils pointent tous vers le même élément au même endroit en mémoire. Je l'utilise fréquemment lorsque je dois construire une table avec un schéma de toutes les chaînes, de sorte que je n'ai pas à donner un mappage un à un hautement redondant.

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

Objets mutables

J'utilise Python depuis longtemps et je n'ai jamais vu de cas d'utilisation où je ferais ce qui précède avec une instance mutable. Au lieu de cela, pour obtenir, disons, une liste vide modifiable, un ensemble ou un dict, vous devez faire quelque chose comme ceci:

list_of_lists = [[] for _ in columns]

Le trait de soulignement est simplement un nom de variable jetable dans ce contexte.

Si vous n'avez que le numéro, ce serait:

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

Ce _n'est pas vraiment spécial, mais votre vérificateur de style d'environnement de codage se plaindra probablement si vous n'avez pas l'intention d'utiliser la variable et d'utiliser un autre nom.


Avertissements pour l'utilisation de la méthode immuable avec des objets modifiables:

Méfiez-vous de faire cela avec des objets mutables , lorsque vous changez l'un d'eux, ils changent tous parce qu'ils sont tous le même objet:

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

foo retourne maintenant:

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

Mais avec des objets immuables, vous pouvez le faire fonctionner parce que vous changez la référence, pas l'objet:

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

Mais encore une fois, les objets mutables ne sont pas bons pour cela, car les opérations sur place modifient l'objet, pas la référence:

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
la source
26

Itertools a une fonction juste pour ça:

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

Bien sûr, itertoolsvous donne un itérateur au lieu d'une liste. [e] * nvous donne une liste, mais, selon ce que vous ferez de ces séquences, la itertoolsvariante peut être beaucoup plus efficace.

Jochen Ritzel
la source
13

Comme d'autres l'ont souligné, l'utilisation de l'opérateur * pour un objet mutable duplique les références, donc si vous en changez une, vous les changez toutes. Si vous souhaitez créer des instances indépendantes d'un objet mutable, votre syntaxe xrange est la façon la plus Pythonique de le faire. Si vous êtes gêné par une variable nommée qui n'est jamais utilisée, vous pouvez utiliser la variable de soulignement anonyme.

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

devrait marcher

Scientifique fou
la source