arrays - F# 为什么在映射函数来对数组中的每个数组进行置乱时,数组不会以不同的方式进行置乱

标签 arrays .net f#

我编写了一个函数来打乱一个数组并映射一个数组数组以打乱每个数组,但它们的打乱方式相同

let rand = System.Random()
let shuffle (rand : System.Random)(array :int[] ) =   let rng = new Random()   
                                                      let mutable n = array.Length       
                                                      while (n > 1) do
                                                          let k = rng.Next(n)  
                                                          n <- n - 1                    
                                                          let temp = array.[n]     
                                                          array.[n] <- array.[k]
                                                          array.[k] <- temp
                                                      array

let playsarray =  shuffle rand 
let scrambledarray =  Array.map (fun x -> playsarray x  )
let playsarra = fun (array : int[]) ->  array |> playsarray
let smallarray =  [1..10].ToArray()
let megaarray = Array.create 10 smallarray
let megarrayscrambled = megaarray |> scrambledarray
megarrayscrambled |> Seq.iter (fun y -> printfn "Ar: %A" y)

运行代码后,所有 10 个数组在数据 ej 中的顺序相同

  • Ar:[|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]
  • Ar:[|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]等等...

最佳答案

您的代码有两个问题。

首先,你的shuffle函数需要 rand参数但实际上并未使用它:在函数内创建一个新的 System.Random实例并使用它而不是使用传入的实例。docs for the System.Random constructor (在示例中)提到默认构造函数使用当前时间作为种子,因此如果两个 Random对象是快速连续创建的,它们将具有相同的种子,从而产生相同的值。要解决此问题,您只需停止创建新的 Random您的 shuffle 中的实例函数并使用传入的函数(我将其从 rand 重命名为 rng,这样其余代码就不需要更改)。这是你的shuffle进行更改后的函数(并且具有更易于阅读的缩进:您不必将函数的第一行与 = 符号在同一行开始;您可以将其放在下一行,然后缩进一级,四个空格):

let shuffle (rng : System.Random) (array : int[]) =
    let mutable n = array.Length  // The number of items left to shuffle (loop invariant).
    while (n > 1) do
        let k = rng.Next(n)  // 0 <= k < n.
        n <- n - 1           // n is now the last pertinent index;
        let temp = array.[n] // swap array[n] with array[k] (does nothing if k == n).
        array.[n] <- array.[k]
        array.[k] <- temp
     array

但是这还不能解决您的问题,因为您还误解了Array.create作品。它创建一个给定大小的数组,其中数组中的每个项目都包含您传入的值。即 megarrayscrambled 中的每个条目数组包含对相同 smallarray 的引用。如果你这样做了megarrayscrambled.[0].[0] <- 999您会看到这改变了 megarrayscrambled 中的十个条目中的每一个,因为它们是同一个数组。

你真正想要的是使用 Array.init ,不是Array.createArray.init接受一个函数并为您正在构建的数组中创建的每个项目运行该函数一次。这意味着如果该函数返回 [1..10].ToArray() ,那么每次调用它时都会返回一个不同数组,因此您将得到您期望的结果。 (顺便说一句,您可以通过执行 [|1..10|] 更简单地创建一个数组,这就是我将在下面的示例代码中使用的)。

所以只需更改您的 let megaarray行至:

let megaarray = Array.init 10 (fun _ -> [|1..10|])

然后您应该会看到您期望的结果。

顺便说一句,还有一个小细节:在一行中你有 Array.map (fun x -> playsarray x) ,但这仅相当于 Array.map playsarray ,阅读起来更简单一些。

关于arrays - F# 为什么在映射函数来对数组中的每个数组进行置乱时,数组不会以不同的方式进行置乱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57156068/

相关文章:

php从一个txt文件中分解新行内容

.net - 什么最适合桌面小部件(占地面积小且图形漂亮)?

.net - Nihbernate 和 MySql : Failed to find or load the registered .Net Framework 数据提供程序

c++ - 将文件内容读入动态分配的 char* 数组——我可以改为读入 std::string 吗?

javascript - 如何将两个数组缩减为存在于同一索引处的单个值?

c++ - 为什么在 C++ 中,我不需要取消引用指向数组的指针来访问数组中的项

c# - 直到 socket.Close 才收到 Windows socket.Send 数据

F#:有效的前缀运算符是什么?

f# - 是否可以强制 .NET F# 编译器在模块中生成 CIL 字段?

f# - 如何在列表中找到出现函数最大值的值