1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Python]enumを使って多次元配列をするときの注意点

Last updated at Posted at 2022-03-13

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 

Reference

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?