1

使用 F#,我想生成一个代表 Bingo 卡的二维数组。宾果卡每列必须有唯一编号。下面是我现在所拥有的,这会根据列生成具有适当尺寸和数字范围的卡片,但这并不能解决唯一性部分。

let generateCard =
    let randNumberGen = new Random()
    Array2D.init 5 5 (fun i j -> randNumberGen.Next((i * 15) + 1, ((i + 1) * 15 + 1)))

我不是在寻找一种必要的方式来做到这一点。我可以在 C# 中轻松地做到这一点,但我正在努力寻找更好的方法来使用函数式/F# 风格来实现这一点。

4

3 回答 3

4

这是解决问题的一种方法。代码的结构与您的版本不同 - 我正在生成一个数组(行),然后使用array2D. 每行中的值是使用uniqueNumbers函数生成的,该函数使用给定的随机数生成器(函数)生成一系列唯一数字。

为了生成唯一的数字,我们使用递归循环并保留一组generated数字。当我们生成一个新数字时,我们首先检查该数字是否不在生成的集合中(如果是,我们尝试另一个)。请注意,如果您需要更多的唯一数字,这会变慢(但这在本示例中可能不是问题):

let uniqueNumbers generator =
  let rec loop generated = seq {
    let n = generator()
    if Set.contains n generated then
      yield! loop generated 
    else
      yield n
      yield! loop (Set.add n generated) }
  loop Set.empty  

现在我们可以通过迭代行索引 0 到 4 来生成一张卡片,并且我们生成一个具有唯一编号的行(我们使用 5 个唯一编号来构建每一行):

let generateCard =
  let randNumberGen = new Random()
  [ for i in 0 .. 4 ->
      uniqueNumbers (fun () -> randNumberGen.Next((i * 15) + 1, ((i + 1) * 15 + 1)))
      |> Seq.take 5 ]
  |> array2D
于 2013-06-19T13:34:06.907 回答
1

唯一的列和行。

open System;
let r = new Random();
let generator n = fun (_) -> r.Next() % n

let uniqueColumns cols g =
   let rec fn  list =
       let row = Seq.take cols (Seq.distinct g) |> Seq.toList
       let anyEqual a b = Seq.zip a b |> Seq.exists (fun (a,b)->a=b)
       seq {
       if Set.exists (anyEqual row) list then
           yield! fn  list
       else
           yield row
           yield! fn  (Set.add row list)
       }
   fn Set.empty
;;

let g = Seq.initInfinite (generator 10)
uniqueColumns 5 g
|> Seq.take 4 
|> Seq.toList

输出

[[6; 3; 7; 4; 8]; 
 [7; 6; 8; 9; 5]; 
 [0; 7; 1; 3; 4];
 [5; 4; 3; 7; 0]]
于 2013-06-19T14:41:10.853 回答
1

通过分解出一些谓词来对上述答案进行变体

open System;

let r = new Random();
let generator n = fun (_) -> r.Next() % n

// generic function for detecting distinctness via Predicate
let rec distinctBy pred ss =
    let set = ref Set.empty
    seq {
        for s in ss do
          if Set.contains s set.Value |> not then
            yield s
            set.Value <- Set.add s set.Value                       
      };;

// A generator for columns
let newRow cols = fun (_) -> 
    Seq.initInfinite (generator 10) 
    |> Seq.take cols 
    |> Seq.toList

let anyEqual a b = Seq.zip a b |> Seq.exists (fun (a,b)->a=b)

// A Generator for rows
Seq.initInfinite (newRow 4)
  |> distinctBy anyEqual
  |> Seq.take 5 
  |> Seq.toList;;

输出

[[6; 3; 7; 4; 8]; 
 [7; 6; 8; 9; 5]; 
 [0; 7; 1; 3; 4];
 [5; 4; 3; 7; 0]]
于 2013-06-19T15:21:33.073 回答