要素を知る
前章で変数の塊「配列変数」について紹介しました。
ココで「1つ以上の要素で構成し、各要素への代入、及び参照は、添字番号を使用する」ことも紹介し、
代入時は、自動的に要素が増えるのでエラーにはならなくなくなっているものの、
参照時は、まだ存在しない要素を取り出すとエラーになることを注意しました。
プログラム内で直接dim命令、ddim命令、sdim命令、ldim命令を使用して要素を確保した場合には、
要素を幾つ設定したのかは、スクリプトを見れば確認ができ、前章書いたような繰り返し命令で、
何回繰り替えせば全要素を参照できるかが分かります。
しかし、配列要素は自動的に増えると言うように書いてます。
つまり、意図していない箇所で知らず知らずのうちに要素数が変化して、
繰り返す回数も変えなければならないということが十分にありうるわけです。
それに、例え配列要素数が増減しないとしても、書いたプログラムを見て要素数を知るのではなく、
プログラムを使って要素数を知る必要がいつかは来ることでしょう。
要素数 = length(変数名)
要素数指定した配列変数の大きさを受け取るもの。
変数名調査する変数を指定する。
配列要素数を知る為の命令は、HSP2には存在しなかった、このlength命令になります。
HSP2以前で配列を含む変数の情報を取得するには、少し高度な命令を使用しなければなりませんでしたが、
HSP3からは標準命令で提供されている為、簡単な手続き(命令の使用)だけでイケるようになりました。
HSP2を使っている人で配列の要素数を知りたい方はTIPSに載せていますのでご覧ください。
さて、命令内容に入る前に上記の命令紹介を見てもらうと、今までとは異なった書き方なので説明します。
今回から新しい書き方にするよ、というわけではなく、実際に今回少し異なる種類なのです。
中学・高校でも習った(習う)数学でもあります(ありました)が、
プログラムの世界で「y = f(x)」という書き方を関数と呼んでいるので覚えましょう。
数学では「左辺yと右辺f(x)は同じ」というような意味合いだったかと思いますが、
「変数 = 値」は「変数は値と同じ」ではなく「変数に値を代入」と言うのと同じで、
プログラムで「y = f(x)」は「右辺f(x)の結果を左辺yに代入」というような意味合いです。
プログラム界でよく見かけるものですが、HSPの世界では、HSP3から新しく登場した形式になります。
プログラムを初めて間もない方や、HSP2しかやったことない方等には少し取っ付き難いかもしれません。
今までの命令というのは一方通行のものでした。
命令に変数やら定数やらをパラメータとして渡すと、命令内部でなにやら処理されて終了です。
しかし、関数と言うのは、関数に変数やら定数やらの値をパラメータとして渡すと、
関数内部で何やら処理した後、その結果を返してくるのです。
命令は、命令に渡すパラメータが最重要(と言ってもこれだけしかポイントがない)ですが、
関数は関数にパラメータを渡すことも重要ではあるものの、
関数内部で処理した結果(返り値、戻り値等と呼ぶ)をどうこうするのが関数としての最重要ポイントです。
主に、何らかの情報を取得・加工するものが関数になります。
情報を設定・配置したりするようなものは返り値を受け取ってもあまり意味がありません。
こういうのは関数の返り値ではなく、通常の一方通行である命令となるのが一般的です。
値の設定系でも正常に処理されたかの結果が知りたいことは多いと思います。
こういうものは、関数の返り値としてではなく、
以前から何度か出現しているシステム変数に値がセットされるということが多いです。
命令が正常に完了したかの結果を代入するシステム変数はstatというものになります。
このstatはいろいろな処理状態(Status)を格納しますので、
命令を実行してから、statでその命令の結果を取得するまでの間に何か別の命令を実行するのは危険です。
その命令でもstatに状態をセットして、意図していない情報を取得することになる恐れがあるからです。
後程その結果が知りたい場合は、システム変数ではなく通常の変数に退避させ、
その変数値から取得するようにしてください。
このstatについては、然るべき時に再度説明します。
話を戻しまして、length関数は配列変数の要素数を取得するものです。
パラメータに任意の変数を渡すことで、その変数の要素数がlength関数の返り値として入ります。
命令紹介のところで、「指定した配列変数の大きさを受け取るもの」という書き方をしていますが、
コレは別に変数でなくても構わないのです。
ソレは「123 = length(変数)」といった定数でもいける、と言う意味ではなく、
左辺の何かに代入する、と言うことでなくてもよいということです。
どういうことかと言うと、算数や数学で括弧を使った式が出てきますよね。
その式の解く順は、括弧の中にあるものから演算を行い、徐々に括弧の外に流れていきます。
「A + ((B + C) * D)」というのは、「B+C」の後に「D」を掛けて「A」を足します。
関数もこのような入れ子にできると言うことです。
つまり、「変数 = 関数大( 関数中( 関数小1(値), 関数小2(値) ) )」と関数を入れ子にすることで、
「関数小1()」と「関数小2()」が処理され、それぞれ結果を「関数中()」のパラメータとして使用。
さらには、「関数中()」の返り値を「関数大()」のパラメータとして使用し、その結果を変数に入れる。
要は、左辺に代入ではなく、外側の関数のパラメータとしても使用できると言うわけです。
関数の説明をしたところで、length関数を実際に使用してみましょう。
 1
 2
 3
 4
 5
	ddim v, 5
	v = 0.1, 2.3, 4.5, 6.7, 8.9
	repeat length(v) // 配列変数vの要素数分繰り返す
		mes "v." + cnt + " = " + v.cnt
	loop
使用方法として、このような使い方ができるとというわけです。
1行目のddim命令で要素数を指定している為にrepeat命令にその回数を書けばいいのですが、
自分が判断してその回数を書くのではなく、プログラムに判断させることに意味があります。
サンプルでは実数型の配列要素数を取得しましたが、整数型、文字列型でも取得できます。
ただ、文字列型の要素数は「sdim 変数, ココ」で言うところの「ココ」ではないので注意してください。
sdim命令の第2パラメータは、紹介時にも書いたように文字数です。
配列の要素数は第3パラメータ以降になりますので、そこだけは気をつけるようにしましょう。
 1
 2
 3
	sdim strings, 11, 4
	strings = "あいうえお", "かきくけこ", "さしすせそ", "たちつてと"
	mes length(strings)
サンプルの様に配列にした後にlength関数で取得をすると、確かに要素数が確認されました。
 1
 2
 3
	sdim strings, 11, 4, 2 // 2次元目も作ってみる
	strings.0.1 = "あいうえお", "かきくけこ", "さしすせそ", "たちつてと"
	mes length(strings) // 表示されるものは…?
しかし、このサンプルの様に二次元配列以上になると、二次元目以降の要素数が取得できませんね。
length関数を実行すると、要素数「4」が返り、「2」が返って来ませんでした。
確かに「4」は配列要素数であり、正しいものが取得できましたが、
「2」も要素数であるのに取得することができませんでしたね。
実は、length関数というものは、「『1次元目の』配列要素数を取得する関数」なのです。
つまり、length関数で二次元目以降の要素数を取得することはできないのですが、
コレは、配列要素の二次元目以降が取得できない、と言っているわけではありませんので悪しからず。
length関数では取得できないだけで、別の取得する関数がちゃんと用意されてます。
二次元目要素数 = length2(変数名)
二次元目要素数指定した配列変数の大きさを受け取るもの。
変数名調査する変数を指定する。
二次元目の要素数を取得する関数は、length2関数になりますが、
使い方はlength関数同様である為に、説明するまでもないと思います。
書いておきますと、length2関数のパラメータに配列変数を渡すことで、二次元目の要素数が返ります。
説明で分からない方や実際の書き方を知りたい方は、下記スクリプトをご覧ください。
length関数の時に説明しておくべきでしたが、length2関数でまとめて説明します。
変数が配列ではない時にlength関数を、一次元のみの時にlength2関数を使用してもエラーとはなりません。
要素数「0」が返るだけですので、使用に際して気をつけなければならないと言うことはありません。
補足を入れるまでもないと思いますが、念のためにしておきますと、
この関数は二次元目の要素数のみを取得しますので、一次元目や三次元目は取得できません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
	dim array, 3, 3
	array.0.0 = 1, 2, 3
	array.0.1 = 4, 5, 6
	array.0.2 = 7, 8, 9
	repeat length2(array) // 2次元目
		out = cnt
		repeat length(array) // 1次元目
			mes array.cnt.out
		loop
	loop
三次元目は、「アレだろうな」とイメージできている方もいると思います。
三次元目要素数 = length3(変数名)
三次元目要素数指定した配列変数の大きさを受け取るもの。
変数名調査する変数を指定する。
配列の三次元目要素数を取得するには、上記length3関数を用います。
使用方法は、length関数、length2関数と同じですので説明は不要でしょう。
しかし、length関数、length2関数を見ていない方がいらっしゃるかもしれません。
そういったことがありますし、講座ですから説明はさせていただきましょう。
length3関数を使うと、三次元目の配列要素数が結果として受け取ることができます。
length2関数でも書いたように、もしも指定配列変数が二次元までしかなくてもエラーにはならずに、
要素数として0が返るだけです。
使い方は下記のサンプルを参考にしてアレンジしてください。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
	ddim triangle, 4, 3, 2
	triangle(0,0,0) = 11.1, 111.11, 1111.111, 11111.1111
	triangle(0,1,0) = 22.2, 222.22, 2222.222, 22222.2222
	triangle(0,2,0) = 33.3, 333.33, 3333.333, 33333.3333
	triangle(0,0,1) = 44.4, 444.44, 4444.444, 44444.4444
	triangle(0,1,1) = 55.5, 555.55, 5555.555, 55555.5555
	triangle(0,2,1) = 66.6, 666.66, 6666.666, 66666.6666
	repeat length(triangle) // 1次元目の要素数分繰り返す
		first = cnt
		repeat length2(triangle) // 2次元目の要素数分繰り返す
			second = cnt
			repeat length3(triangle) // 3次元目の要素数分繰り返す
				third = cnt // 特に入れなくてもよいが,他と揃える為に入れておく
				pos first * 180, second * 50 + third * 150
				mes triangle.first. second.third
			loop
		loop
	loop
二次元配列要素数を取得する時のサンプルスクリプトでは、
外側のrepeat命令で二次元目を、内側のrepeat命令で一次元目配列要素数を取得、
つまり、次元の大きいものから繰り返しましたが、今回は小さいほうから繰り返してます。
考えると分かるかと思いますが、順番はどれが先になってもよいので、
実際の、今回のサンプルで言うところの15行目の、対応要素指定が間違えなければ構わないでしょう。
配列は四次元まで指定可能でしたので、四次元目を取得する関数も存在します。
順番に講座を読んでいただいた方には、もはや不要な領域ですね。
四次元目要素数 = length4(変数名)
四次元目要素数指定した配列変数の大きさを受け取るもの。
変数名調査する変数を指定する。
length4関数が四次元目配列要素数を取得するものとなります。
前章で「多次元(特に三次元以上)はわかりにくくなるだけなので使わないで」と書きましたし、
その注意書きがなくても、三次元以上の指定をすること自体がレアパターンでしょうから、
使用頻度はかなり低いものと思われます。
しかし、三次元配列くらいなら、HSPで3D系ソフトも作られることですし、
「変数(横,縦,奥)」という書き方で座標管理することが、あるかもしれませんけどね。
レアであろうと、使える以上は講座として紹介しておきましょう。
length4関数のパラメータに変数を指定することで、四次元目の要素数を取得できます。
あるなら「1」以上の設定要素数が、なければ「0」が返ります。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	dim square, 2, 2, 2, 2
	square.0.0.0.0 = 10, 15
	square.0.1.0.0 = 20, 25
	square.0.0.1.0 = 30, 35
	square.0.1.1.0 = 40, 45
	square.0.0.0.1 = 50, 55
	square.0.1.0.1 = 60, 65
	square.0.0.1.1 = 70, 75
	square.0.1.1.1 = 80, 85
	repeat length(square) // 1次元目
		first = cnt
		repeat length2(square) // 2次元目
			second = cnt
			repeat length3(square) // 3次元目
				third = cnt
				repeat length4(square) // 4次元目
					fourth = cnt
					pos first * 50 + second * 100, third * 50 + fourth * 100
					mes square.first.second.third.fourth
				loop
			loop
		loop
	loop
HSP3では、配列要素数を知る>length系関数が追加され、repeat命令で回数として使うことで、
全要素数を繰り返せらるようになりましたが、もう一種類の別命令が用意されています。
foreach 配列変数名
配列変数名繰り返し回数となる配列変数を指定する。
foreach命令は、繰り返し回数を要素数としてループさせる為のものです。
パラメータの配列変数の要素数分をループするわけだから、
「repeat length(変数)」としていたものが、「foreach 変数」に書き換えた、と言った感じです。
繰り返しの命令は、終端の対となる命令も別に存在していましたが、
foreach命令の対となる終端命令は、repeat命令と同じloop命令になります。
ループの途中で終わらせることや、現在ループ回数の変更も行うことができるようになっており、
強制的にループを終わらせるものはbreak命令、現在回数の変更はcontinue命令、と
repeatループと同じ様になってます。
 1
 2
 3
 4
 5
	v = 9, 8, 7, 6, 5, 4, 3, 2, 1 // 要素数宣言していないが、要素数は「9」
	foreach v // vの要素分繰り返す
		pos (cnt \ 3 + cnt / 3) * 50, cnt / 3 * 50 // 段々に位置指定(特に意味はない)
		mes v.cnt
	loop
多言語に登場するforeachはもう少し使い勝手がイイのですが、
HSPのforeach命令はループ回数にしかなり得ませんので、どうかなという気が少しします。
ヘルプには、モジュール変数なら云々、と書かれていますが、
この場ではとりあえず関係ないので無視して、短いですがforeachは終了としておきます。
要素数を知るものとしてコレくらいで終わりましょうか。
関数と言う目新しいものが出てきました。
関数はこのほかにも様々存在するので、関数の存在とその使い方を覚えていてください。