Background
paizaスキルチェック のある問題を解いていたときに、2次元配列を使ってある区画の範囲に色を塗るといった処理が必要となりました。そこで各要素を列挙型を使ってみたのですが思った処理結果が出なかったので紹介します。
Initialize
ここで色の列挙型と区画を初期化してみます。
class Color(Enum):
WHITE = 0
RED = 1
GREEN = 2
BLUE = 3
# width:5 height:4 の2次元配列を作る
mat = [[Color.WHITE] * 4] * 5
for r in mat:
for c in r:
print(c.name, end=" ")
print("\n")
WHITE WHITE WHITE WHITE
WHITE WHITE WHITE WHITE
WHITE WHITE WHITE WHITE
WHITE WHITE WHITE WHITE
WHITE WHITE WHITE WHITE
Issue
上記で設定した区画から (LEFT, TOP) = (2,2) (RIGTH, BOTTOM) = (3,4)
の部分に赤色を塗りたい場合、
for r in range(1,4):
for c in range(1,3):
mat[r][c] = Color.RED
WHITE RED RED WHITE
WHITE RED RED WHITE
WHITE RED RED WHITE
WHITE RED RED WHITE
WHITE RED RED WHITE
なぜか2列目と3列目が全色赤になって1行目と5行目も塗ってしまいます。
WHY?
てことで、各要素と各行のオブジェクトIDを出力してみます。
mat = [[Color.WHITE] * 4] * 5
for r in mat:
for c in r:
print(id(c))
print("[List]:{}".format(id(r)))
140539104199104
140539104199104
140539104199104
140539104199104
[List]:140539104158848
140539104199104
140539104199104
140539104199104
140539104199104
[List]:140539104158848
140539104199104
140539104199104
140539104199104
140539104199104
[List]:140539104158848
140539104199104
140539104199104
140539104199104
140539104199104
[List]:140539104158848
140539104199104
140539104199104
140539104199104
140539104199104
[List]:140539104158848
リストに同一のIDが振られています。 おそらくですが、[[(obj)] * num ] * num
にすると列ごとのコピーは浅いコピーと判断されるみたいです。 浅いコピーについてですが公式では 浅いコピー (shallow copy) は新たな複合オブジェクトを作成し、その後 (可能な限り) 元のオブジェクト中に見つかったオブジェクトに対する 参照 を挿入します。
となっていて要素自体を完全にコピーしておらずリンクだけが複製されています。
Solution
pattern 1
python標準を使う場合は下記の通り。これで各行のリストのオブジェクトIDが重複しないので上記のような色を塗っても他の行には影響しないです。
mat = []
for r in range(5):
#各行を作成
row = []
for c in range(4):
row.append(Color.WHITE)
mat.append(row)
pattern 2
numpyを使う場合です。 np.array
にラッピングします。
おそらくですがpaizaでスキルチェックしたい場合は使えないと思います。
import numpy as np
mat = np.array([[Color.WHITE] * 4]*5)
output
pattern1とpattern2のどちらで設定しても下記の結果が出力されると思います。
for r in range(1,4):
for c in range(1,3):
mat[r][c] = Color.RED
for r in np_mat:
for c in r:
print(c.name, end=" ")
print("\n")
WHITE WHITE WHITE WHITE
WHITE RED RED WHITE
WHITE RED RED WHITE
WHITE RED RED WHITE
WHITE WHITE WHITE WHITE