it-swarm.dev

Die eleganteste Möglichkeit, Elemente verschachtelter Listen zu ändern

Ich habe eine 2D-Liste, die so aussieht:

table = [['donkey', '2', '1', '0'], ['goat', '5', '3', '2']]

Ich möchte die letzten drei Elemente in Ganzzahlen ändern, aber der folgende Code fühlt sich sehr hässlich an:

for row in table:
    for i in range(len(row)-1):
        row[i+1] = int(row[i+1])

Aber ich hätte lieber etwas, das aussieht:

for row in table:
    for col in row[1:]:
        col = int(col)

Ich denke, es sollte eine Möglichkeit geben, den Code oben zu schreiben, aber das Slice erstellt eine Iterator/neue Liste, die vom Original getrennt ist, sodass die Referenzen nicht übernommen werden. 

Gibt es eine Möglichkeit, eine weitere Pythonic-Lösung zu erhalten?

28
Conrad.Dean
for row in table:
    row[1:] = [int(c) for c in row[1:]]

Sieht oben pythonischer aus?

20
Shekhar

Versuchen:

>>> for row in table:
...     row[1:]=map(int,row[1:])
... 
>>> table
[['donkey', 2, 1, 0], ['goat', 5, 3, 2]]

Wenn Sie AFAIK einem list-Slice zuweisen, wird die Ausführung der Operation erzwungen, anstatt ein neues list zu erstellen.

13
MAK

Ich mag die Antwort von Shekhar sehr. 

Wenn Sie beim Schreiben von Python-Code for i in range(len(somelist)) schreiben, tun Sie es in der Regel falsch:

  • versuchen Sie enumerate, wenn Sie eine einzige Liste haben
  • versuchen Sie Zip oder itertools.izip, wenn Sie zwei oder mehr Listen haben, die Sie parallel durchlaufen möchten

In Ihrem Fall ist die erste Spalte anders, sodass Sie die Aufzählung nicht elegant verwenden können:

for row in table:
    for i, val in enumerate(row):
        if i == 0: continue
        row[i] = int(val)
8
gurney alex

Ihr "hässlicher" Code kann nur durch Aufruf von range mit zwei Argumenten verbessert werden:

for row in table:
    for i in range(1, len(row)):
        row[i] = int(row[i])

Dies ist wahrscheinlich das Beste, was Sie tun können, wenn Sie darauf bestehen, die vorhandenen Elemente zu ändern, ohne neue temporäre Listen zuzuordnen (entweder mit einem Listenverständnis, map und/oder einem Slicing). See Gibt es ein In-Place-Äquivalent zu "Map" in Python?

Obwohl ich es nicht empfehlen kann, können Sie diesen Code auch allgemeiner gestalten, indem Sie Ihre eigene In-Place-Map-Funktion einführen:

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)

Ich persönlich finde das weniger Pythonic. Es gibt vorzugsweise nur einen naheliegenden Weg, und das ist es nicht.

3
Wesley

Listenlisten verwenden:

table = [row[0] + [int(col) for col in row[1:]] for row in table]
1

Das wird funktionieren:

table = [[row[0]] + [int(v) for v in row[1:]] for row in table]

Möglicherweise möchten Sie jedoch die Konvertierung an dem Punkt durchführen, an dem die Liste zuerst erstellt wird.

0
Keith