3

リストの要素をシャッフルしようとしています:

(* Returns a list with the same elements as the original but in randomized order *)
let shuffle items = 
    items
    |> List.map (fun x -> (x, System.Random().Next()))
    |> List.sortBy snd
    |> List.map fst

ただし、次の理由により、これは常にitems同じ順序で返されます。

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];;
val it : (int * int) list = [(1, 728974863); (2, 728974863); (3, 728974863)]

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];;
val it : (int * int) list =
  [(1, 1768690982); (2, 1768690982); (3, 1768690982)]

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];;
val it : (int * int) list = [(1, 262031538); (2, 262031538); (3, 262031538)]

System.Random().Next()各呼び出しで常に同じ値を返すのはなぜですか? 連続する呼び出しが時系列的に近すぎるためですか? または、他の方法で API を誤用していますか?

(注:この答えは私にとってはうまくいきますが、なぜこの動作が現れるのか知りたいです。)

4

3 に答える 3

9

System.Random() のデフォルト コンストラクターのマニュアルで最もよく説明されています。

デフォルトのシード値はシステム クロックから派生し、有限の分解能を持ちます。その結果、既定のコンストラクターの呼び出しによって連続して作成されるさまざまな Random オブジェクトは、同じ既定のシード値を持つため、同じ乱数のセットが生成されます。

于 2012-08-15T18:46:53.673 に答える
4

心に留めておくべきことの 1 つは、乱数ジェネレーターから一連の数値を生成するのではなく、一連の乱数ジェネレーターを作成し、それぞれの最初の乱数を生成していることです。

System.Random().Next()は の省略形であるため、(new System.Random()).Next()Random の既定のコンストラクターを使用して、反復ごとに新しい System.Random オブジェクトを作成します。他の回答で述べたように、そのデフォルトのコンストラクターは現在の時間の粗い値を RNG の初期シードとして使用するため、すばやく連続して呼び出されると、本質的に毎回同じ RNG を再作成します (その上で同じ数を生成します)。最初で唯一の呼び出し)。

解決策は、System.Random オブジェクトを 1 つだけ作成し、それを再利用することです。

> let rng = new System.Random() in List.map (fun x -> x, rng.Next()) [1; 2; 3];;
val it : (int * int) list = [(1, 483259737); (2, 719806274); (3, 1951956175)]
于 2012-08-15T21:15:34.663 に答える
3

毎回同じシード値を使用しているため、このように機能します。そのため、 の同じインスタンスを連続して呼び出すことが重要ですRandom

于 2012-08-15T18:46:04.993 に答える