久しぶりにこっち系のネタでも書いてみます。
VBAで書かれている計算ツールをpythonに移植してFlaskアプリに組み込んでwebで動かせるようにする(例のpythonanywhere使用)ってことをここ1か月ぐらいずっとやっています。
普通の四則計算や累乗、対数、三角関数とかだったらimport mathしてちょこちょこっと手を加えるだけで良いのですが、単純な仕組みの割に結構ネックで、そのうえ分量が多いので2週間ぐらい費やしたことがあります。
それは配列のインデックスです。
多くの方は数字を順番に数えるとき、1,2,3・・・と1から数え始めると思うんですよ。
その感覚通りVBAの配列要素のインデックス番号は1から始めます。
Xという名前の配列があるとして、
X=["福原","遥","柊","まいん"] の場合先頭に入っているものすなわちX(1)は"福原"ってわけです。
ところがどっこい、pythonの場合はインデックス番号が0から始まるため、
VBAの感覚で先頭の要素を出力しようとしてX[1]を出力しようとすると"遥"が出てきてしまいます。
pythonで先頭の要素である"福原"を出力するにはX[0]とする必要があります。
(X(1)とX[0]のようにそもそも括弧の形が違いますが、配列のインデックス番号を入れる括弧はVBAでは()、pythonは[]を使います)
要するにpythonに置き換えるときは、VBAの元プログラムからインデックス番号を1引けばいいだけじゃんってことなのですが、確かに道中にあるC=F(ns)みたいなのはC=F[ns-1]とするだけなので単純です。
問題なのはforループ中にあるやつです。
ただし単に
For i =1 To N
y = X[i]
Next i
みたいなのは
for i in range(n):
y = X[i]
で対していじる箇所もなく、むしろpythonではiが勝手に0から始まるので1を引く必要もありません。(しかしfor文じゃないのだと引くことになるのでかえってややこしい)
一番罠だったのが、for文中の配列インデックスの括弧内で足し算やら引き算やら掛け算やらが蠢いているやつです。
例えばさ、
配列CがあるとしてまずVBAで
For jj 1 To ns
For ii 1 To ns
y = C(N - (ii - 1) * 2 - (2 * jj - 1))
Next ii
Next jj
Nが8、iiが2、jjが2だとすると
y=C(8-(2-1)*2-(2*2-1))=C(3)
ってなるわけです。pythonではそこから1引くのでC[2]になってほしいわけです。
では、pythonで同じように書くと
for jj in range(ns):
for ii in range(ns):
y = C[N - (ii - 1) * 2 - (2 * jj -1) ]
っていう式になります。
pythonではfor文の起点が0なので、VBAと同じ条件だとiiが1、jjが1になります。(Nは8で同じ)
y = C[8 - (1-1)*2 - (2*1-1) ] = C[7]
はい、C[2]になってほしいのにC[7]になってしまいましたね。
じゃあ、どうすればよかったのかといいますと、
① (ii - 1) * 2 の部分で、
iiがVBAよりも1小さいだけでなく、括弧外2倍掛けられています。
なので、この部分で-2する必要がありました。
② (2 * jj -1)の部分で括弧内になりますがjjに直接2倍掛けられています。
この部分も-2する必要がありました。
③ そもそもNについてはiiとかjjとかの起点が0というのは関係ないので
python故に-1する必要がありました。
なので①~③合わせて-5する必要がありました。
for jj in range(ns):
for ii in range(ns):
y = C[N - (ii - 1) * 2 - (2 * jj -1) - 5]
で、3行目がy = C[2]になるので、これが正答となります。
つまり、思考停止で配列のインデックス番号をVBAの場合より-1すればいいという単純な話ではないということです。