J'ai une liste en 2D qui ressemble à ceci:
table = [['donkey', '2', '1', '0'], ['goat', '5', '3', '2']]
Je veux changer les trois derniers éléments en entiers, mais le code ci-dessous est très moche:
for row in table:
for i in range(len(row)-1):
row[i+1] = int(row[i+1])
Mais je préfère avoir quelque chose qui ressemble à:
for row in table:
for col in row[1:]:
col = int(col)
Je pense qu'il devrait y avoir un moyen d'écrire le code ci-dessus, mais la tranche crée un itérateur/une nouvelle liste qui est distinct de l'original, afin que les références ne soient pas reportées.
Y a-t-il un moyen d'obtenir une solution plus Pythonic?
for row in table:
row[1:] = [int(c) for c in row[1:]]
Est-ce que ci-dessus semble plus pythonique?
Essayer:
>>> for row in table:
... row[1:]=map(int,row[1:])
...
>>> table
[['donkey', 2, 1, 0], ['goat', 5, 3, 2]]
D'après les informations dont je dispose, l'attribution d'une tranche list
force l'opération à effectuer sur place au lieu de créer une nouvelle variable list
.
J'aime beaucoup Shekhar répondre.
En règle générale, lorsque vous écrivez du code Python, si vous vous trouvez en train d'écrire for i in range(len(somelist))
, vous le faites mal:
enumerate
si vous avez une seule listeZip
ou itertools.izip
si vous souhaitez parcourir deux ou plusieurs listes en parallèle.Dans votre cas, la première colonne est différente et vous ne pouvez donc pas utiliser élégamment énumérer:
for row in table:
for i, val in enumerate(row):
if i == 0: continue
row[i] = int(val)
Votre code "moche" peut être amélioré en appelant simplement range
avec deux arguments:
for row in table:
for i in range(1, len(row)):
row[i] = int(row[i])
C'est probablement ce que vous pouvez faire de mieux si vous insistez pour changer les éléments en place sans allouer de nouvelles listes temporaires (en utilisant une compréhension de liste, map
et/ou un découpage en tranches). Voir Existe-t-il un équivalent sur place de "carte" en python?
Bien que je ne le recommande pas, vous pouvez également généraliser ce code en introduisant votre propre fonction de carte in-situ:
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)
Personnellement, je trouve cela moins Pythonic. Il n'y a de préférence qu'une seule façon évidente de le faire, et ce n'est pas ça.
Utiliser les compréhensions de liste:
table = [row[0] + [int(col) for col in row[1:]] for row in table]
Cela fonctionnera:
table = [[row[0]] + [int(v) for v in row[1:]] for row in table]
Cependant, vous voudrez peut-être songer à effectuer la conversion au moment où la liste est créée pour la première fois.