ユニークでランダムな整数を返却する JavaScript コード
getOtherRandomInt という関数として作成いたしました。
ユニークな数値を得たいですので、除外対象となる数値を配列で引数として渡します。
また、返却する乱数は範囲を指定できるように最小値と最大値をそれぞれ引数として渡します。実際に人間に使って貰う場合を想定いたしますと、たとえば 10 桁の数を返却するのは覚え辛く実用的ではございません。1 〜 1000 と範囲を指定することで、覚えやすい数値を返すことを可能にしております。
コードを試すには、コードをコピーして Google Chrome のデベロッパーツールの Console に貼り付けて enter キーを押してくださいまし♪
/** * numberArray 配列に無く、かつ、min から max までの範囲の * 乱整数を返却します。 * 返却できる乱整数がない場合は undefined を返却します。 * @param {array} numberArray 除外対象となる数値の一次元配列 * @param {number} min 乱数の最小値 * @param {number} max 乱数の最大値 * @return {number|undefined} min から max までの乱整数。返却できる乱整数がない場合は undefined */ function getOtherRandomInt(numberArray, min, max) { // min から max までの配列を生成 var minMaxArray = []; var count = max - min + 1; for (var i = 0; i < count; i++) { minMaxArray[i] = min; min++; } // 返却対象となる数値を抽出 // minMaxArray から numberArray と一致する要素を除去 var candidateArray = minMaxArray.filter(function(element, index, array) { // this は filter の第 2 引数の numberArray return (this.indexOf(element) === -1); }, numberArray); // 返却乱数の配列要素番号を生成 // candidateArray (返却乱数候補の数値が入った配列) の要素数を範囲として乱数を生成 var candidateArrayLengthRandom = getRandomInt(0, candidateArray.length - 1); // 返却乱数を配列から取り出して返却 var randomInt = candidateArray[candidateArrayLengthRandom]; return randomInt; } /** * 指定した数値内の乱整数を返却します。 * @param {number} min 乱数の最小値 * @param {number} max 乱数の最大値 * @return {number} min から max までの乱整数 */ function getRandomInt(min, max) { return Math.floor( Math.random() * (max - min + 1) ) + min; } // サンプル console.log(getOtherRandomInt([1, 2, 3, 4, 5], 1, 10)); // 6 ~ 10 のいずれか console.log(getOtherRandomInt([-1, 0, 1], -1, 1)); // undifined
ポイント
- 除外対象となる数字が、乱数生成範囲からはみ出している場合は、そもそも無視されます。たとえば次の場合、5 〜 10 の乱数が返却されます。
- numberArray: [1, 2, 3, 4, 555555]
- min: 1
- max: 10
- ロジックとしては、候補となる乱整数を絞り込んでから返却するように書きました。もうすこし流れを詳しく書くと、次のようになります。
- 乱整数の範囲で配列を生成
- この配列から、対象外となる数字を除去
- ランダムに要素数を選択し、対応する値を返却
おまけ。最初に書いていて捨てたコード
ひよコードですの♪その理由です。(最初、クソース、ウンコードと書いていましたけれども、ひよコードの方が未来に溢れていて素敵ですの。かわいいですし♪)
- 乱数が得られなかった場合、永遠に while ループ処理が終わらない
ですので、冒頭の完成コードでは無限ループは起こりえないように書きなおしました。
こちらの方が短いコードを書くことができて、(while(true) から目を逸らしながら)最初は喜んでいたのですけれどもね><。
/** * 配列には無い乱整数を返却します。 * 乱整数の範囲は min から max までです。 * @param {number} array 数値を含んだ一次元配列 * @param {number} min 乱数の最小値 * @param {number} max 乱数の最大値 * @return {number} min から max までの乱整数 */ function getOtherRandomInt(array, min, max) { while (true) { // 乱整数を生成し、一覧に無い場合に返却 var randomInt = getRandomInt(min, max); if (array.indexOf(randomInt) === -1) { return randomInt; } } } /** * 指定した数値内の乱整数を返却します。 * @param {number} min 乱数の最小値 * @param {number} max 乱数の最大値 * @return {number} min から max までの乱整数 */ function getRandomInt(min, max) { return Math.floor( Math.random() * (max - min + 1) ) + min; } // サンプル console.log(getOtherRandomInt([1, 2, 3, 4, 5], 1, 10)); // 6 ~ 10 のいずれか console.log(getOtherRandomInt([-1, 0, 1], -1, 1)); // 無限ループ
おわりに
配列の扱いって難しいですの!for ループでぐるぐる回さなければならないかしら><、嫌ですの><、と思っておりました。
以前関数型プログラミングについての文章をなんとなく読んだ時に、配列を扱うときにループを使わないで処理するようなことを読んだ記憶がございました。
そこで調べてみたところ、次のページが参考になりました!
filter 関数についての詳細はこちらですわ。
この関数、ループを使わないで短くかけて素敵♪内部ではループしているのでしょうけれども。
ただし、外部から変数を渡すことができません><。動的に抽出条件を指定したい場合はどうするのかしら?そんな用途に気がつかないはずはございませんから、きっと渡す方法があるはず。。。。ありました!次のページが参考になりました!ありがとう存じます!
あらためて Array.prototype.filter() – JavaScript | MDN を見てみますと、オプション引数の thisObject にしっかりと説明がございました><。
理解できていなかっただけですの。てへ♪
また、乱数の生成関しては、次のページのサンプルをそのまま使用させていただきました。便利な関数にまとまっております♪
配列に指定した値があるかどうかは、indexOf メソッドで判定しますけれども、こちらを参考にいたしました。
ちなみ、「ひよコード」の出典はこちらです。こちらのページで紹介されていた、ツイートですの。
美しくないコードをuncodeとかクソースなどと呼ぶ人もいるようですが、これらの言葉は開発者を傷つけるので、最近アプレッソでは、あまり美しくないコードを「ひよコード」、美しくない箇所は「ここがピヨピヨしてる」と表現するようにしています。未熟だけど伸び代はあることを意味しています。
— 小野 和俊/Kazutoshi Ono (@lalha2) July 5, 2012
以上です。