[[0]*m]*nの注意点
最近、C言語で書いていたMASのコードをpythonに書き直してみようかといろいろ画策しております。ですが、C言語でできたことがpythonでもできるわけではなかったりするので注意が必要です。私の場合、得てして、ベクトルや行列を扱いたいわけで、その代替品がリストや配列です。
- リストと配列は違う
pythonには配列が存在しないので、リストを配列のように使うことが多いと思います。numpyのarrayを使う人はそちらのほうがよいと思いますが、僕はあいにく使っていないので、現時点では生のpythonでやることにします。
さて、次のような0を含む配列の配列に、一定数の個数1を代入したいとすれば、僕はC言語で次のように記述します。
#include<stdio.h> #define N 10 #define Ns 3 int main(){ int i,j,k=0; int a[N][N]; for(i=0;i<N;i++) for(j=0;j<N;j++) a[i][j]=0; while(k<Ns){ i=rand()%N; j=rand()%N; if(a[i][j] == 0) { k++; a[i][j] = 1; } } for(i=0;i<N;i++) {for(j=0;j<N;j++) printf("%d ",a[i][j]);printf("\n");} }
そうすると、次のように行列を表示してくれます。
$ gcc -o array array.c $ ./array.exe 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
pythonで同じことをしようとしたところ、初期値0の入力で、気を抜くと変なことが起こる場合があるので注意が必要です。
>>> a = [[0]*3]*3#ここがだめ >>> a [[0, 0, 0], [0, 0, 0], [0, 0, 0]] >>> a[0][0] 0 >>> a[0][0]=1 >>> a [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[0]*m]*nって別段普通に使えると思ってたのですが。いざ代入しようと思った時に僕としては、一か所だけ変更したくても、つられて一列変わっちゃうわけで。これは、使いにくい。折角短くかけるのに、どうしてこうなるの~。
ちゃんとやろうと思ったら、
>>> a = [[0 for i in range(3)] for j in range(3)] >>> a [[0, 0, 0], [0, 0, 0], [0, 0, 0]] >>> a[0][0] = 1 >>> a [[1, 0, 0], [0, 0, 0], [0, 0, 0]]
これならちゃんと、一か所だけ変わってくれます。なんで揃ってないのだろうか。うーん、"zen of python"なんでしょうきっと。
まぁ、ともあれ、ちゃんと意図した動きをしてくれるコードは以下のようになりました。
import random Lx, Ly = 3, 3 a = [[0 for i in range(Lx)] for j in range(Ly)] k = 0 Ns = 2 while k < Ns: i, j = random.randrange(Lx), random.randrange(Ly) if a[i][j] == 0: k += 1 a[i][j] = 1 [print(i) for i in a]
インデックスkを必要としない書き方ができるならそうしたいものです。
おまけにクラスを使っても書いてみよう。
class Matrix: def __init__(self, raw, col): self.Lx = raw self.Ly = col self.m = [[0 for i in range(raw)] for j in range(col)] def show(self): [print(i) for i in self.m] def puts(self, sup): import random k = 0 while k < sup: i, j = random.randrange(self.Lx), random.randrange(self.Ly) if self.m[i][j] == 0: k += 1 self.m[i][j] = 1 if __name__ == "__main__": a = Matrix(3,3) a.puts(3) a.show()