web-dev-qa-db-ja.com

入れ子になったリストの要素を適切に変更する最もエレガントな方法

次のような2Dリストがあります。

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

最後の3つの要素を整数に変更したいのですが、以下のコードは非常に醜く感じます。

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

しかし、私はむしろ次のようなものを望んでいます:

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

上記のコードを書く方法があるはずだと思いますが、スライスはオリジナルとは別のイテレータ/新しいリストを作成するため、参照は引き継がれません。

もっとPythonicソリューションを取得する方法はありますか?

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

上記はよりpythonicに見えますか?

20
Shekhar

試してください:

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

申し訳ありませんが、listスライスに割り当てると、新しいlistを作成する代わりに、操作が強制的に実行されます。

13
MAK

私はシェカールがたくさん答えるのが好きです。

一般的なルールとして、Pythonコードを記述しているときに、for i in range(len(somelist))を記述していることに気づいた場合、それは間違っています。

  • リストが1つしかない場合はenumerateを試してください
  • 並行して繰り返し処理したいリストが2つ以上ある場合は、Zipまたはitertools.izipを試してください。

あなたの場合、最初の列が異なるため、列挙をエレガントに使用することはできません。

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

「醜い」コードは、2つの引数を指定してrangeを呼び出すだけで改善できます。

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

これは、新しい一時リストを割り当てずに(リスト内包、map、および/またはスライスを使用して)アイテムを適切に変更することを主張する場合に実行できる最善の方法です。参照 Pythonの「マップ」に相当するインプレースはありますか?

お勧めしませんが、独自のインプレースマップ関数を導入して、このコードをより一般的なものにすることもできます。

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)

個人的には、これはlessPythonicだと思います。それを行うには明らかな方法が1つだけあることが望ましいが、これはそうではない。

3
Wesley

リスト内包表記を使用:

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

これは動作します:

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

ただし、リストが最初に作成された時点で変換を行うことを検討したい場合があります。

0
Keith