初始化每列具有唯一编号的数组

时间:2013-06-19 13:19:32

标签: .net f#

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

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

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

3 个答案:

答案 0 :(得分:4)

这是解决问题的一种方法。代码的结构与您的版本不同 - 我生成一个数组(行)数组,然后使用array2D将其转换为2D数组。使用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

答案 1 :(得分: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]]

答案 2 :(得分: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]]