Crear una lista de un solo elemento repetido N veces
Quiero crear una serie de listas, todas de diferentes longitudes. Cada lista contendrá el mismo elemento e
, repetido n
veces (donde n
= longitud de la lista).
¿Cómo creo las listas sin utilizar una lista de comprensión [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
en realidad no crea la lista, simplemente crea un objeto que puede usarse para crear una lista si lo desea! Intentemos eso nuevamente, pero convirtiéndolo a una lista:
>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233
Entonces, si quieres una lista, usa [e] * n
. Si desea generar los elementos de forma perezosa, utilice repeat
.
>>> [5] * 4
[5, 5, 5, 5]
Tenga cuidado cuando el elemento que se repite es una lista. La lista no será clonada: ¡todos los elementos harán referencia 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 un solo elemento repetido n veces en Python
Dependiendo de su caso de uso, querrá utilizar diferentes técnicas con diferente semántica.
Multiplica una lista de elementos inmutables
Para elementos inmutables, como Ninguno, bools, ints, floats, strings, tuplas o frozensets, puedes hacerlo así:
[e] * 4
Por ejemplo:
>>> [None] * 4
[None, None, None, None]
Tenga en cuenta que esto generalmente solo se usa con elementos inmutables (cadenas, tuplas, conjuntos congelados, etc.) en la lista, porque todos apuntan al mismo elemento en el mismo lugar en la memoria.
Como ejemplo de caso de uso, uso esto cuando tengo que crear una tabla con un esquema de todas las cadenas, para no tener que realizar una asignación uno a uno altamente redundante.
schema = ['string'] * len(columns)
Multiplica la lista donde queremos que se repita el mismo elemento con estado mutable
Multiplicar una lista nos da los mismos elementos una y otra vez. La necesidad de esto es poco frecuente:
[iter(iterable)] * 4
A veces esto se utiliza para asignar un iterable a una lista de listas:
>>> iterable = range(12)
>>> a_list = [iter(iterable)] * 4
>>> [[next(l) for l in a_list] for i in range(3)] # uninteresting usage
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
Podemos ver que a_list
contiene el mismo iterador de rango cuatro veces:
>>> from pprint import pprint
>>> pprint(a_list)
[<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>,
<range_iterator object at 0x7f9fe3b58420>]
elementos mutables
He usado Python durante mucho tiempo y he visto muy pocos casos de uso en los que haría lo anterior con objetos mutables.
En lugar de eso, para repetir, digamos, una lista, un conjunto o un dictado mutable y vacío, deberías hacer algo como esto:
list_of_lists = [[] for _ in iterator_of_needed_length]
El guión bajo es simplemente un nombre de variable descartable en este contexto.
Si solo tienes el número, ese sería:
list_of_lists = [[] for _ in range(4)]
El _
nombre desechable no es realmente especial, pero un analizador de código estático probablemente se quejará si no tiene intención de utilizar la variable y utilizar cualquier otro nombre.
Advertencias sobre el uso del método de multiplicación con elementos mutables:
Tenga cuidado al hacer esto con objetos mutables , cuando cambia 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 nuevamente, los objetos mutables no sirven para esto, porque las operaciones in situ 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'])]