ポク太郎です。
プログラムはサラッと短いコードで見やすくするのが基本。理由は、全ステップに意味があるので、これは何だっけ?と常に再考する必要があるから。
そのためによく使うのはループ→それにはやはり要素番号指定だけで使える配列変数が便利。
というわけで、配列変数を使いこなすため、サッと配列の指定要素を削除したり、挿入・追加して配列を再構築してしまう方法を考えています。
関数への値渡しと参照渡し
左側のメインから右側の関数へ引数を渡しますが、渡し方に“値渡し”と“参照渡し”(C++と同じものと思ってもいいのかな?)があります。
値渡し
![[UWSC]配列の要素の削除と挿入・追加[参照渡し使用]【自作関数】](/img/phy/pc/uwsc/20171015_uwsc1.png)
関数へはメインのローカル変数Aの値を教えて、関数内RESULTの値をメインのローカル変数Bに代入します。
このとき、関数は変数Aの値を教えてもらってるだけなので、関数内からはメインの変数Aを一切更新することができません。
参照渡し
![[UWSC]配列の要素の削除と挿入・追加[参照渡し使用]【自作関数】](/img/phy/pc/uwsc/20171015_uwsc2.png)
関数へはメインのローカル変数Aそのものを渡して(在り処を教えてる?)、関数内RESULTの値をメインのローカル変数Bに代入します。
このとき、関数はメインのローカル変数Aそのものを預かっている(に等しい)ので、関数内で引数Cを更新すると、メインのローカル変数である変数Aも更新されてしまいます。
この参照渡しを実現するには、関数の宣言文FUNCTIONでの引数の定義を“var 引数”とします。
通常は値渡しを使用。でも都合の悪い場合=「戻り値が配列、かつ、要素数が関数内で変化してしまった場合」が存在。
UWSCでは下の一文書くだけで関数の戻り配列が全要素コピーされます。
今回の目的は配列の再構築=要素の削除、挿入・追加→関数を通る前後で要素数が変化。その場合、「要素数が違うよ」とエラーが出て止まってしまいます。
そこで、この“参照渡し”を使用し、呼び出し側が一行で済むように作ります。
C言語が賞賛された理由はすべて独立な関数で構成し、他人数開発に移行できるから→関数内からメインの変数を書き換えできちゃう方法はできる限り排除すべき⇒「“参照渡し”使用したのはこの部分だけ」と“特殊扱い”した部分と常に思い出せる重要部にしか使わないよう努めます。
配列の要素の削除remove()関数
FUNCTION remove(var a[],rn)
IF rn<0 or rn>LENGTH(a)-1
PRINT "ポクエラー(remove関数):無効な要素番号が削除指定されました。"
RESULT=0
ELSE
FOR i=rn TO LENGTH(a)-1-1
a[i]=a[i+1]
NEXT
RESIZE(a,LENGTH(a)-1-1)
RESULT=1
ENDIF
FEND
1,12行目 | 1 12 | FUNCTION remove(var a[],rn) FEND |
remove関数宣言:引数rnの要素番号を渡された配列から削除する関数 引数a[]: 再構築する配列 引数rn: 削除する要素番号 | ||
2,5,11行目 | 2 5 11 | IF rn<0 or rn>LENGTH(a)–1 ELSE ENDIF |
引数rnが配列の有効な要素数を指定しているかを判定。 無効な要素番号(-値や最大要素番号より大)⇒3、4行目へ 有効な要素番号⇒6~10行目へ | ||
3,4行目 | 3 4 | PRINT “ポクエラー(remove関数):無効な要素番号が削除指定されました。“ RESULT=0 |
エラーを表示し、関数の戻り値は0を返す。 | ||
6~10行目 | 6 7 8 9 10 | FOR i=rn TO LENGTH(a)–1–1 a[i]=a[i+1] NEXT RESIZE(a,LENGTH(a)–1–1) RESULT=1 |
引数rnから最大要素番号の一つ手前までをループし、一つ上の要素番号の内容を配列a[i]に代入していきます。 済んだら配列を最大要素番号より一つ小さくリサイズします。 関数の戻り値として1を返します。 |
配列の要素の挿入・追加append()関数
FUNCTION append(var a[],an,dt)
RESIZE(a,LENGTH(a)-1+1)
IF an<0 or an>LENGTH(a)-1
a[LENGTH(a)-1]=dt
ELSE
FOR i=LENGTH(a)-1 TO an step -1
IF i=an
a[i]=dt
ELSE
a[i]=a[i-1]
ENDIF
NEXT
ENDIF
RESULT=1
FEND
1,15行目 | 1 15 | FUNCTION append(var a[],an,dt) FEND |
append関数宣言:引数anの要素番号位置に配列要素を挿入・追加する関数(引数anに-値や最大要素番号より大を指定された場合は最後に追加する仕様) 引数a[]: 再構築する配列 引数an: 挿入する位置の要素番号 引数dt: 要素番号anの位置に入れたい内容 | ||
2行目 | 2 | RESIZE(a,LENGTH(a)–1+1) |
まず、配列の最大要素番号を現在より一つ大きくリサイズします。 RESIZE(a,現在の最大要素番号+1) | ||
3,5,13行目 | 3 5 13 | IF an<0 or an>LENGTH(a)–1 ELSE ENDIF |
引数anが配列の有効な要素数を指定しているかを判定。 無効な要素番号(-値や最大要素番号より大)⇒4行目へ 有効な要素番号⇒6~12行目へ | ||
4行目 | 4 | a[LENGTH(a)–1]=dt |
現在の最大要素番号の位置(2行目で既に一つ大きくしているので)に引数dtを代入します。 | ||
6~12行目 | 6 7 8 9 10 11 12 | FOR i=LENGTH(a)–1 TO an step –1 IF i=an a[i]=dt ELSE a[i]=a[i–1] ENDIF NEXT |
最大要素番号から引数anまでをループします。(step -1として大きい方から順番に) 引数anのときは引数dtを代入、違うときは一つ下の要素番号の内容を配列a[i]に代入していきます。 | ||
14行目 | 14 | RESULT=1 |
関数の戻り値として1を返します。 |
配列要素の削除と挿入・追加動作確認
動作確認用プログラムがこちら。
DIM test[10]
FOR i=0 TO LENGTH(test)-1
test[i]=i*2
PRINT test[i]
NEXT
PRINT "--最大要素番号は"+LENGTH(test)-1
rn=8
remove(test,rn)
PRINT "--要素"+rn+"を削除"
FOR i=0 TO LENGTH(test)-1
PRINT test[i]
NEXT
PRINT "--最大要素番号は"+LENGTH(test)-1
an=5
dt=51
append(test,an,dt)
PRINT "--要素"+an+"に"+dt+"を追加"
FOR i=0 TO LENGTH(test)-1
PRINT test[i]
NEXT
PRINT "--最大要素番号は"+LENGTH(test)-1
1~6行目 | 1 2 3 4 5 6 | DIM test[10] FOR i=0 TO LENGTH(test)–1 test[i]=i*2 PRINT test[i] NEXT PRINT “––最大要素番号は“+LENGTH(test)–1 |
配列test[10]を準備し、要素番号x2の値を代入してテスト用配列を作成、表示します。最後に最大要素番号を表示しておきます。 | ||
8~14行目 | 8 9 10 11 12 13 14 | rn=8 remove(test,rn) PRINT “––要素“+rn+“を削除“ FOR i=0 TO LENGTH(test)–1 PRINT test[i] NEXT PRINT “––最大要素番号は“+LENGTH(test)–1 |
変数rnを設定して、作成したremove()関数を呼び出した後、完成したテスト用配列を表示します。最後に最大要素番号を表示。 | ||
16~23行目 | 16 17 18 19 20 21 22 23 | an=5 dt=51 append(test,an,dt) PRINT “––要素“+an+“に“+dt+“を追加“ FOR i=0 TO LENGTH(test)–1 PRINT test[i] NEXT PRINT “––最大要素番号は“+LENGTH(test)–1 |
変数anと変数dtを設定して、作成したappend()関数を呼び出した後、完成したテスト用配列を表示します。最後に最大要素番号を表示。 |
動作確認結果がこちら。
0 2 4 6 8 10 12 14 16 18 20 --最大要素番号は10 --要素8を削除 0 2 4 6 8 10 12 14 18 20 --最大要素番号は9 --要素5に51を追加 0 2 4 6 8 51 10 12 14 18 20 --最大要素番号は10
要素8を削除すると、test[8]の16が無くなり最大要素番号が一つ小さく9となります。
要素5に51を追加すると、test[5]に51が代入、以降は後ろへ一つづつずれて、最大要素番号が一つ大きい10になってくれました。
8、16行目の値を変更して試してみてください。
配列の最大要素を返す関数 | 関数の引数と戻値に配列変数【使い方まとめ】 | 配列の要素の削除と挿入・追加【参照渡し】 |
○配列の再構築のやり方
配列の要素の削除する関数
配列の要素の挿入・追加する関数
コメント