Crear una lista de elementos únicos repetidos n veces en Python

Sé que una lista de comprensión hará esto, pero me preguntaba si hay un enfoque aún más corto (¿y más Pythonic?).

Quiero crear una serie de listas, todas de longitud variable. Cada lista contendrá el mismo elemento e, repetido n veces (donde n = longitud de la lista). ¿Cómo creo las listas, sin hacer?

[e for number in xrange(n)] 

para cada lista?

También puedes escribir:

 [e] * n 

Debe tener en cuenta que si e es, por ejemplo, una lista vacía, obtendrá una lista con n referencias a la misma lista, no n listas vacías independientes.

Pruebas de rendimiento

A primera vista, parece que repetir es la forma más rápida de crear una lista con 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 

Pero espera, no es una prueba justa …

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

La función itertools.repeat no crea realmente la lista, simplemente crea un objeto que puede usarse para crear una lista si lo desea. Intentemos eso de nuevo, pero convirtiéndonos en una lista:

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

Así que si quieres una lista, usa [e] * n . Si quieres generar los elementos perezosamente, usa repeat .

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

Tenga cuidado cuando el elemento que se repite es una lista. La lista no se clonará: ¡todos los elementos se referirán a la misma lista!

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

Crear una lista de elementos únicos repetidos n veces en Python

Artículos inmutables

Para elementos inmutables, como Ninguno, cuerdas, tuplas o frozensets, puede hacerlo así:

 [e] * 4 

Tenga en cuenta que lo mejor es usarlo solo con elementos inmutables (cadenas, tuplas, frozensets,) en la lista, porque todos apuntan al mismo elemento en el mismo lugar en la memoria. Uso esto con frecuencia cuando tengo que construir una tabla con un esquema de todas las cadenas, de modo que no tenga que dar una asignación uno a uno.

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

Artículos mutables

He usado Python durante mucho tiempo y nunca he visto un caso de uso en el que haría lo anterior con una instancia mutable. En su lugar, para obtener, digamos, una lista, un conjunto o un dictado vacíos mutables, debe hacer algo como esto:

 list_of_lists = [[] for _ in columns] 

El guión bajo es simplemente un nombre de variable desechable en este contexto.

Si solo tienes el número, sería:

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

El _ no es realmente especial, pero su verificador de estilo de entorno de encoding probablemente se quejará si no tiene la intención de usar la variable y de utilizar ningún otro nombre.


Advertencias para el uso del método inmutable con elementos mutables:

Ten cuidado de hacer esto con objetos mutables , cuando cambias uno de ellos, todos cambian porque todos son el mismo objeto:

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

foo ahora regresa:

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

Pero con objetos inmutables, puedes hacer que funcione porque cambias la referencia, no el 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([])] 

Pero, de nuevo, los objetos mutables no son buenos para esto, porque las operaciones en el lugar cambian el objeto, no la referencia:

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

Itertools tiene una función solo para eso:

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

Por supuesto itertools te da un iterador en lugar de una lista. [e] * n te da una lista, pero, dependiendo de lo que harás con esas secuencias, la variante de itertools puede ser mucho más eficiente.

Como han señalado otros, el uso del operador * para un objeto mutable duplica las referencias, por lo que si cambia uno, puede cambiarlos todos. Si desea crear instancias independientes de un objeto mutable, su syntax de rango extraño es la forma más Pythonic de hacerlo. Si le molesta tener una variable con nombre que nunca se usa, puede usar la variable de subrayado anónimo.

 [e for _ in xrange(n)] 
 [e] * n 

Deberia trabajar