python - tuplas - La forma más elegante de modificar elementos de listas anidadas en su lugar
metodos de listas en python (7)
Esto funcionará:
table = [[row[0]] + [int(v) for v in row[1:]] for row in table]
Sin embargo, es posible que desee pensar en hacer la conversión en el punto donde se creó la lista por primera vez.
Tengo una lista 2D que se ve así:
table = [[''donkey'', ''2'', ''1'', ''0''], [''goat'', ''5'', ''3'', ''2'']]
Quiero cambiar los últimos tres elementos a números enteros, pero el siguiente código se siente muy feo:
for row in table:
for i in range(len(row)-1):
row[i+1] = int(row[i+1])
Pero prefiero tener algo que parezca:
for row in table:
for col in row[1:]:
col = int(col)
Creo que debería haber una forma de escribir el código anterior, pero la división crea un iterador / nueva lista que es independiente del original, por lo que las referencias no se transfieren.
¿Hay alguna manera de obtener una solución más Pythonic?
Esto logra lo que buscas. Es una solución legible. Puedes ir por uno similar usando listcomp también.
>>> for row in table:
... for i, elem in enumerate(row):
... try:
... int(elem)
... except ValueError:
... pass
... else:
... row[i] = int(elem)
...
Me gusta mucho la respuesta de Shekhar.
Como regla general, al escribir el código Python, si te encuentras escribiendo f or i in range(len(somelist))
, lo estás haciendo mal:
- Intenta
enumerate
si tienes una sola lista - intente
zip
oitertools.izip
si tiene 2 o más listas que desea iterar en paralelo
En su caso, la primera columna es diferente, por lo que no puede utilizar enumerar con elegancia:
for row in table:
for i, val in enumerate(row):
if i == 0: continue
row[i] = int(val)
Tratar:
>>> for row in table:
... row[1:]=map(int,row[1:])
...
>>> table
[[''donkey'', 2, 1, 0], [''goat'', 5, 3, 2]]
AFAIK, la asignación a un segmento de list
obliga a la operación a realizarse en lugar de crear una nueva list
.
Tu código "feo" se puede mejorar simplemente llamando al range
con dos argumentos:
for row in table:
for i in range(1, len(row)):
row[i] = int(row[i])
Esto es probablemente lo mejor que puede hacer si insiste en cambiar los elementos en su lugar sin asignar nuevas listas temporales (ya sea utilizando una lista de comprensión, un map
o un corte). Ver ¿Hay un equivalente en el lugar a ''mapa'' en python?
Aunque no lo recomiendo, también puede hacer que este código sea más general introduciendo su propia función de mapa en el lugar:
def inplacemap(f, items, start=0, end=None):
"""Applies ``f`` to each item in the iterable ``items`` between the range
``start`` and ``end``."""
# If end was not specified, make it the length of the iterable
# We avoid setting end in the parameter list to force it to be evaluated on
# each invocation
if end is None:
end = len(items)
for i in range(start, end):
items[i] = f(items[i])
for row in table:
inplacemap(int, row, 1)
Personalmente, encuentro esto menos pitónico. Preferiblemente, solo hay una manera obvia de hacerlo, y esta no es esta.
Utilice la lista de comprensión:
table = [row[0] + [int(col) for col in row[1:]] for row in table]
for row in table:
row[1:] = [int(c) for c in row[1:]]
¿Se ve más arriba el pitón?