2024/08/28

連番のリスト値の生成

今回も開発中の dxl ナンプレ のハイスコア機能に関するお話です。

内部的には、ハイスコアを記録した、ユーザ名、クリア時間、クリア日次をリスト値で保持しています。各リスト値の 1 番目が 1 位、次が 2 位という風にノーツではありがちな値の持たせ方ですね。

これを、ランキングとして表示する場合には、やはり順位の表示が必要です。今回はこの順位をリスト値の件数だけ表示するコードを紹介します。

必要な順位数を取得するために、今回も Sec フィールドを利用しています。このフィールドに値がない場合、ハイスコアがない状態。3 個のリスト値の場合は 3 位まで存在する状態という前提です。


リスト値を利用した方法

まずは、このブログ開始当初に紹介した方法の応用です。以下の記事では、Excel の列番号である A ~ Z、AA ~ ZZ のリストを作成する方法について紹介しました。

Excel の列文字列を式で算出

その時の技を使用すると次のような式になります。

xLst := "0":"1":"2":"3":"4":"5":"6":"7":"8":"9";
xIdx := @Elements(Sec);
@If(xIdx = 0;
   "";
   @Subset(@Subset(xLst;-9) : (@Subset(xLst;-9)*+xLst); xIdx)
);

ポイントは @If の中身ですね。

まず、以下の式は、0 ~ 9 の 後ろから 9 要素なので、1 ~ 9 となります。

@Subset(xLst;-9)

その後ろ、以下の部分が 10 ~ 99 までを一括作成しています。

(@Subset(xLst;-9)*+xLst)

”*+” が順列演算子と呼ばれるもので、リスト値同士をすべての組み合わせで加算し、それぞれのリスト値を返す仕様でした。

この 2 つの結果を ":" 演算子でリスト値としてつなげ、1 ~ 99 のリスト値を作成。最後に @Subset を使用して必要な順位までのリスト値を切り出しています。


Excel の列番号は A スタートでしたが、今回は 1 から始まる数字になります。また、2桁になった場合、00 ではなく 10 となるので、@Subset(xLst;-9) を使ってうまく調整しています。


この方法では、リスト演算を習得していないとパッと見て何をしているのかわかりにくいですよね。また、ハイスコアで 99 位まで表示することはそうそうありませんので、無駄が多いと言えます。

そこで今回は方法、ループの関数である @For で作成してみます。


@For ループで実現した場合

@For 関数は Notes 6 から搭載された関数です。私はそれ以前から Notes で開発していたため、リスト演算の方をよく使います。

今回、あえて @For を使ってみましたが、つまづいた部分があったのでまとめておきます。


まず、ヘルプを見ながら、次のようなコードを作成してみました。

xIdx := @Elements(Sec);

@For(xNum := 1; xNum <= xIdx; xNum := xNum + 1;
   xLst := xLst : xNum
);
xLst

xNum がループ変数で 1 から必要な順位数まで順にループさせます。

xLst 変数が順位の値をリスト値としてためる変数で、1、2、3 … と格納する想定で作成しました。ところが、この式ではエラーが発生して動作しません。

どうやら、xLst の初期値が文字列で、以下の演算の初回実行でエラーが出ているようです。

   xLst := xLst : xNum


そこで、xLst に数値の初期値 1 を与えるようにしました。また、1 は必ずセットされるのでループは 2 からのスタートとし、最後にランキングがない場合は "" となるように調整しました。

これで、無事エラーもなく順位が表示されるようになりました。

xIdx := @Elements(Player);

xLst := 1;
@For(xNum := 2; xNum <= xIdx; xNum := xNum + 1;
   xLst := xLst : xNum
);
@If(xIdx = 0; ""; xLst)

久しぶりに @For を使ってみました。プログラムはリスト演算よりわかりやすい印象を受けましたが、変数の初期化が必要な点が少しクセがありますね。


なお、今回の事例では、リスト演算の結果は文字列リスト、@For ループの場合は数値リストとなっております。ご注意ください。


0 件のコメント:

コメントを投稿