web-dev-qa-db-fra.com

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

Je sais qu'une compréhension de liste suffira, mais je me demandais s'il existait une approche encore plus courte (et plus pythonique?).

Je veux créer une série de listes, toutes de longueur variable. Chaque liste contiendra le même élément e, répété n fois (où n = longueur de la liste). Comment créer les listes sans faire

[e for number in xrange(n)]

pour chaque liste?

445
chimeracoder

Vous pouvez aussi écrire:

[e] * n

Vous devriez 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 est 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.repeat ne crée pas réellement la liste, elle crée simplement un objet qui peut être utilisé pour créer une liste si vous le souhaitez! Essayons à nouveau, mais en convertissant 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 voulez générer les éléments paresseusement, utilisez repeat.

672
Mark Byers
>>> [5] * 4
[5, 5, 5, 5]

Soyez prudent lorsque l'élément en cours de répétition 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]]
125
gaefan

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

Articles immuables

Pour les éléments immuables, tels que Aucun, les chaînes, les n-uplets ou les frozensets, vous pouvez le faire comme ceci:

[e] * 4

Notez que cette option est mieux utilisée uniquement avec les éléments immuables (chaînes, tuples, frozensets,) de la liste, car ils pointent tous sur le même élément au même endroit en mémoire. Je l'utilise fréquemment lorsque je dois créer une table avec un schéma de toutes les chaînes, de sorte que je n'ai pas à donner un mappage un à un.

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

Objets Mutable

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. Par exemple, pour obtenir une liste vide, un ensemble ou un dict mutable, vous devriez faire quelque chose comme ceci:

list_of_lists = [[] for _ in columns]

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

Si vous avez seulement le numéro, ce serait:

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

Le _ 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.


Mises en garde concernant l'utilisation de la méthode immuable avec des objets mutables:

Faites attention avec les objets mutables, quand vous en changez un, ils changent tous parce qu'ils sont tous le même objet :

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

foo revient 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 changent 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'])]
58
Aaron Hall

Itertools a une fonction juste pour ça:

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

Bien sûr, itertools vous donne un itérateur au lieu d'une liste. [e] * n vous donne une liste, mais, en fonction de ce que vous ferez avec ces séquences, la variante itertools peut être beaucoup plus efficace.

23
Jochen Ritzel

Comme d'autres l'ont fait remarquer, l'utilisation de l'opérateur * pour un objet mutable duplique les références. Ainsi, si vous en changez un, vous les modifiez toutes. Si vous souhaitez créer des instances indépendantes d'un objet mutable, votre syntaxe xrange est la manière la plus pythonique de le faire. Si vous êtes dérangé par le fait d'avoir une variable nommée qui n'est jamais utilisée, vous pouvez utiliser la variable de soulignement anonyme.

[e for _ in xrange(n)]
10
W.P. McNeill
[e] * n

devrait marcher

7
Mad Scientist