JavaScript ループ内の乱数による予期しない動作
生成中 JavaScript の乱数 これは、配列を操作する場合の一般的なタスクです。ただし、そのような操作にループを使用すると、予期しない結果が発生することがあります。注目すべき問題は、複数の反復で同一の値または予測可能な値が生成される場合です。
この記事では、2 つの for ループが 2 つの異なる配列から乱数を生成するという一般的な問題を検討します。最初のループは正しく動作しますが、2 番目のループは毎回同じ値のシーケンス、特に数値 30、29、28、27、および 26 を返しているように見えます。
この問題の根本原因を調査し、なぜ問題が発生するのかを理解します。 2 番目の for ループは真のランダム性を生成できません。さらに、この記事ではコードを修正し、各ループが独立して動作するようにするための解決策も提供します。
落とし穴を理解することで、 ランダム化ロジック そしてメソッドはどのように Math.random() 作業を進めれば、将来のプロジェクトでも同様の問題に対処できるようになります。コードをさらに深く掘り下げて間違いを特定し、それを改善する方法について話し合いましょう。
指示 | 使用例 |
---|---|
Math.floor() | 小数点を最も近い整数に切り捨てるために使用されます。ランダム化のコンテキストでは、生成されたランダム インデックスが配列の有効範囲内に収まることが保証されます。 |
Math.random() | 0 (両端を含む) から 1 (両端を含まない) までの 10 進数の疑似乱数を生成します。これは、配列からランダムな要素を選択するために両方のループで使用されるランダム化ロジックの中核です。 |
array.splice() | 配列から要素を削除して返します。このスクリプトでは、要素が選択されると、その後の繰り返しでの繰り返しを避けるために、元の配列からその要素が削除されるようにします。 |
array.at() | 指定されたインデックスにある要素を取得します。このソリューションにとって重要ではありませんが、負のインデックスでも要素に安全にアクセスできることが特に便利です。 |
array.indexOf() | 配列内で指定された要素が見つかった最初のインデックスを返します。要素が存在しない場合は -1 を返します。この方法は当初、要素を見つけるために使用されていましたが、論理的な問題が発生しました。 |
new Set() | 一意の値のみを格納する新しい Set オブジェクトを作成します。単体テストでは、選択されたすべての乱数が一意であることを検証するために使用されます。 |
assert() | テストに使用される単純なアサーション関数。条件が満たされない場合はエラーがスローされ、コードが期待どおりに動作することを確認するのに役立ちます。 |
throw new Error() | アサーションが失敗したときにカスタム エラー メッセージを生成します。これにより、テストの実行中に意味のあるフィードバックが得られます。 |
const | ブロックスコープを持つ変数を宣言します。 const で宣言された変数は再割り当てできないため、主要な関数や配列への誤った変更が防止され、コードの安定性が向上します。 |
JavaScript 配列のランダム化の背後にあるロジックを分析する
提供されるソリューションは、2 つのループが異なる配列から乱数を生成しようとするが、1 つのループが真にランダムな結果を提供できないという一般的な問題に対処します。この問題の主な原因は、 Math.random() が使用されます。元のスクリプトでは、ランダム インデックスを決定するときに計算に +1 が含まれていました。この微妙な間違いにより、プログラムが無効なインデックスを選択することがあり、2 番目のループで 30 から 26 へのカウントダウンのような非ランダムな出力が生成されることがありました。
修正されたソリューションでは、 Math.floor(Math.random() * array.length) 生成されたインデックスが有効であることを確認します。この式の背後にあるロジックは、次の結果を乗算することです。 Math.random() (0 から 1 の間) を配列の長さで割ります。の Math.floor() このメソッドは結果を最も近い整数に切り捨て、インデックスが常に範囲内にあることを保証します。この変更により問題が修正され、ループの各反復で異なる要素がランダムに選択されるようになります。
改善されたソリューションの 1 つは、 配列.splice() 配列から要素を取得および削除します。この方法では、元の配列を直接変更することで重複を防ぎ、以前に選択した要素が後続の反復で使用できなくなるようにします。最初のループはこのロジックで適切に動作し、同様の修正を適用した後の 2 番目のループも同じように動作するようになりました。 splice() を呼び出すたびに、削除された要素が返され、コンソールに出力されます。
もう 1 つの重要な改善には、ランダムな要素を選択するための再利用可能な関数の作成が含まれます。 getRandomFromArray 関数は、ロジックを単一の再利用可能なブロックにカプセル化することでプロセスを簡素化します。このアプローチにより、コードがより保守しやすくなり、理解しやすくなります。さらに、さまざまな環境での機能の正確性を検証するために単体テストが追加されました。の使用 アサート ステートメントは、返された配列の長さが期待どおりであること、および選択されたすべての要素が一意であることを確認するのに役立ちます。このようにコードを構造化することで、ソリューションは機能するだけでなく、堅牢になり、さまざまなシナリオに簡単に適応できるようになります。
JavaScript 配列の反復乱数を理解する
配列のランダム化の問題を解決し、一意のランダム選択を保証するための JavaScript フロントエンド スクリプト
// Solution 1: Correcting the Random Selection Logic
let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
for (let i = 0; i < 5; i++) {
const random = Math.floor(Math.random() * col1.length);
const number = col1.splice(random, 1)[0];
console.log(number);
}
for (let i = 0; i < 5; i++) {
const random = Math.floor(Math.random() * col2.length);
const number = col2.splice(random, 1)[0];
console.log(number);
}
関数型プログラミングによる一意の乱数の確保
配列操作を強化し、再利用性を向上させるための JavaScript フロントエンド関数型プログラミング
// Solution 2: Functional Approach with Reusable Functions
const getRandomFromArray = (array, count) => {
const result = [];
for (let i = 0; i < count; i++) {
const random = Math.floor(Math.random() * array.length);
result.push(array.splice(random, 1)[0]);
}
return result;
};
const col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
console.log(getRandomFromArray(col1, 5));
console.log(getRandomFromArray(col2, 5));
さまざまな環境向けのソリューションのテスト
単体テストを追加して、さまざまなブラウザーにわたるランダム化ロジックを検証する
// Solution 3: Simple Unit Test to Verify Random Output
const assert = (condition, message) => {
if (!condition) {
throw new Error(message || "Assertion failed");
}
};
const testRandomFunction = () => {
const array = [1, 2, 3, 4, 5];
const result = getRandomFromArray([...array], 5);
assert(result.length === 5, "Result length should be 5");
assert(new Set(result).size === 5, "All numbers should be unique");
};
testRandomFunction();
console.log("All tests passed!");
高度な概念: ランダムな配列選択でよくある間違いを回避する
JavaScript で使用すると、 乱数の生成 ループ内では、よくある落とし穴を避けるために慎重に実装する必要があります。不適切なインデックス計算により、意図しない要素や繰り返しの要素が選択される場合、重大な問題が 1 つ発生します。乱数を生成するとき、開発者はインデックスが配列の有効範囲内にあることを確認する必要があります。元のコードに追加すると、 +1 ランダムな式の長さが誤って配列の境界を超えたため、2 番目のループで予期しない動作が発生しました。
もう 1 つの見落とされている問題は、配列操作方法の選択です。その間 splice() 隙間を残さずに要素を削除するには、次の方法を使用します。 indexOf() 誤ってロジックを壊す可能性があります。ランダムに生成された値が配列内に見つからない場合、関数は次の値を返します。 -1、エラーが発生する可能性があります。によって生成されたインデックスを使用して直接スプライシングすることにより、 Math.floor()の場合、有効なインデックスのみがアクセスされるため、コードはこの問題を完全に回避します。
さらに、再利用性とモジュール性は専門能力開発における重要な実践事項です。再利用可能な関数内に機能をカプセル化すると、保守性が向上します。また、コードの重複が回避され、可読性が向上します。単体テストの使用は、特にランダムな要素を扱う場合に、一貫した結果を保証するためのもう 1 つの強力な方法です。アサーションを通じて結果を検証すると、予期しない動作を早期に発見するのに役立ちます。優れたプラクティスを組み合わせることで、開発者は機能要件を満たすだけでなく、さまざまなシナリオで効率的に実行できる堅牢な JavaScript コードを作成できます。
JavaScript 配列のランダム化に関するよくある質問
- なぜ追加するのか +1 配列の長さにするとロジックが壊れますか?
- 追加 +1 配列の長さを超えるインデックスが生成され、無効な選択やエラーが発生する可能性があります。
- どのようにして splice() 要素が繰り返されていないことを確認しますか?
- 選択された要素を配列から削除することで、 splice() 以前に選択した要素が今後の反復で使用できないようにします。
- どうなるか indexOf() 返品 -1?
- もし indexOf() 返品 -1、これは値が配列内に見つからないことを意味し、検証せずに直接使用するとエラーが発生する可能性があります。
- どのようにして Math.random() 乱数を生成する機能?
- Math.random() 0 (両端を含む) と 1 (両端を含まない) の間のランダムな 10 進数を生成します。これは、乗算を使用して目的の範囲に合わせてスケーリングできます。
- コードを関数にカプセル化する利点は何ですか?
- ロジックを関数にカプセル化すると、再利用性、可読性、保守性が向上します。また、コードの重複が防止され、テストが容易になります。
JavaScript 配列のランダム化に関する最終的な考え方
この問題から得られる重要な点は、乱数を扱うときにインデックスを正しく計算することが重要であるということです。 配列。長さに余分な値を追加するなどの小さな間違いにより、予期しない動作が発生し、結果が繰り返し発生する可能性があります。などの正確な方法を使用して、 Math.floor() 有効な選択を保証し、そのようなエラーを防ぎます。
さらに、次のようなメソッドを使用すると、 splice() 選択した要素を削除し、重複を避けるのに役立ちます。再利用可能な関数でロジックをラップすると、コードがより効率的で保守しやすくなります。単体テストなどのベスト プラクティスを適用すると、ランダム化ロジックがさまざまな環境で機能することが検証され、コードの全体的な信頼性が向上します。
JavaScript 配列のランダム化の問題に関するソースとリファレンス
- その方法を説明します Math.random() そして Math.floor() JavaScript でランダムなインデックスを生成するためによく使用されます。続きを読む MDN Web ドキュメント - Math.random() 。
- JavaScript に関する詳細な洞察を提供します。 Array.splice() 方法と、ランダム選択中に重複エントリを回避する際のその重要性について説明します。訪問 MDN Web ドキュメント - Array.splice() 。
- 保守性を向上させ、複雑なコードベースでのロジック エラーを回避するために、JavaScript で再利用可能な関数を構造化するためのベスト プラクティスについて説明します。チェックアウト JavaScript.info - 関数 。
- ランダムな出力を扱う場合にコードの信頼性を確保するための、JavaScript での単体テストの役割について説明します。見る Jest - 単体テストの開始 。