Pythonの2次元リストを扱うときの注意

Pocket

Pythonの2次元リストを使う際に困ったことがあったので整理して残しておきます。


目次


Pythonの2次元リスト

Pythonの2次元リスト(2次元配列)は正確に言えば「リストのリスト」となります。
例えば[1, 2, 3]というリストがあります。
また[4, 5, 6]というリストがあります。
これらをリストの要素とします。
つまり[[1, 2, 3], [4, 5, 6]]となります。
これが「リストのリスト」の意味です。

下は4*3の2次元リストです。

コードだと下のとおりです。

a = [
[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12]
]

位置は次の通り指定します。

2次元リストの初期化

リストを作っておくことを考えます。
1次元であれば次のようにできます。

b = [0] * 2
# [0, 0, 0]

次に4*3の2次元リストを作ります。

b = [[0] * 3] * 4
# [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

便利ですね。
と言いたいところですが、これには落とし穴があります。

Pythonのコピーの挙動

次のようなコードを考えます。

a = [1, 2, 3]
b = a
print(b) # [1, 2, 3]

a[0] = 9 # a に代入しているのに
print(b) # b が [9, 2, 3] になる!

aという変数に[1, 2, 3]というリストを代入します。
bという変数にaを代入します。
bをプリントすると[1, 2, 3]となります。

次にaの最初の要素を9とします。
ここでbをプリントします。aでなくbです。
すると[9, 2, 3]となります。

これがPythonの正しい挙動なのですが、慣れないと酷い目に遭います。

2次元リストを初期化するときの注意

2次元リストを初期化を正しく行わないと期待通りの挙動になりません。

a = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
a[2][1] = 1
print(a)
# [[0, 0, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]]

変数aとして、全ての要素が0の4*3の2次元リストを作ります。
[2][1]の要素を変更します。
リストの要素は0から数えるので3番目、2番めの要素が変更されていることがわかります。

b = [[0] * 3] * 4
print(b)
# [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
b[2][1] = 1
print(b)
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]

変数bとして、同様の2次元リストを作ります。今度は*を使っています。
[2][1]の要素を変更します。
3番目、2番めの要素が変更されるはずですが実際は各リストの2番めの要素が変更されています。
これは意図通りではありません。

正しくは内包表記を使って次のようにします。

b = [[0 for i in range(3)] for j in range(4)]
b[2][1] = 1
print(b)
# [[0, 0, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]]

2次元リストでよくあるエラー

list indices must be integers or slices, not tuple

こんなエラーが出た場合は、2次元リストで要素を指定するときに a[x, y] としているからかもしれません。
正しくは a[x][y] とします。

[ 2022年11月12日 | カテゴリー: Python | タグ: , , , ]

« | »

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

送信してください。


タグ

カテゴリー

最近の投稿

最近のコメント

固定ページ

アーカイブ

stabucky

写真

メタ情報