Python でネストしたリストの更新処理をする

· 3min · Masataka Kashiwagi

Python でリストを複製して,それを更新したい場合はどうするのが良いか.

初期化したリストの更新処理でハマってしまった

今回は,初期化したリストを更新した際にハマってしまった失敗があるので,備忘録として残しておく.詳しい内容は参考サイトに載っている.

Python で決まった形のリストを予め作成しておきたい場合に,以下のようにすることがあると思う.

shape you want: [[0, 0], [0, 0], [0, 0]]  # 要素が2つあるリストが3つ
>>> list1 = [[0] * 2] * 3
>>> list1
[[0, 0], [0, 0], [0, 0]]

そして,上記リストを何かしらの値で更新したい場合を考える.今回だと,[0][0] の要素を更新するとする.

>>> list1[0][0] = 3.5
>>> list1
[[3.5, 0], [3.5, 0], [3.5, 0]]

結果は,各リストの0番目の要素が全て更新される.この原因は,list1 = [[0] * 2] * 3 と書くと,要素のリストが全て同じオブジェクトになってしまい,どこかの要素を変更すると全て変わってしまうから.

対処法

上記の結果を回避するためには,リスト内包表記を使うと解決することができる.先程の例の場合,以下のように書くと良い.

>>> list2 = [[0] * 2 for i in range(3)]
>>> list2
[[0, 0], [0, 0], [0, 0]]

内包表記を使うと,リストはそれぞれ異なるオブジェクトとして扱われる.なので,[0][0] の要素を更新すると,意図した部分だけが更新され問題が発生しない.

>>> list2[0][0] = 3.5
>>> list2
[[3.5, 0], [0, 0], [0, 0]]

リストを初期化する際はこれらに注意しておかないと,本来の意図とは違う動きになってしまう.こうゆうミスを気にしたくない場合には,numpy の array で作りたい shape を作成し,その後にリストに変換しても良い.

>>> np.zeros((2, 3)).tolist()  # 0で初期化
[[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]

# 0以外の場合
np.ones((2, 3)).tolist()  # 1で初期化
np.full((2, 3), 5).tolist()  # 任意の値で初期化

参考


このエントリーをはてなブックマークに追加

ブログ記事を読んで頂き,ありがとうございます!もしこの記事が良かったり参考になったら,「Buy me a coffee」ボタンから☕一杯をサポートして頂けるとモチベーションが上がります!どうぞよろしくお願いします🤩