F#阵列 - 数量是和否

时间:2018-02-13 17:05:18

标签: arrays f#

我有三个数组 - 第一个是一个浮点数组,第二个是一个字符串数组,而第三个是一个包含已排序的浮点数组,来自第一个数组的唯一值。

module SOQN = 

    open System

    type collective = { score:double; yes:int; no:int; correct:double }

    let first  = [| 25;   20;   23;    10;    8;     5;    4;     12;   19;    15;    15;    12;   11;    11 |]
    let second = [| "No"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No" |]

    let third  = Array.distinct (first |> Array.sort)
    let fourth = Seq.zip first second
    let fifth  = fourth |> Seq.sortBy fst
    let yesCounts = 
        fifth 
        |> Seq.filter (fun (_, y) -> if y = "Yes" then true else false)
        |> Seq.map fst
    let noCounts = 
        fifth 
        |> Seq.filter (fun (_, y) -> if y = "No" then true else false)
        |> Seq.map fst

    (*
        Expected Result: 
        third          = [| 4; 5; 8; 10; 11; 12; 15; 19; 20; 23; 25 |]
        yesCounts      = [| 1; 1; 2; 3; 4; 4; 6; 7; 7; 8; 8 |]
        noCounts       = [| 0; 1; 1; 1; 2; 4; 4; 4; 5; 5; 6 |]
        yesProportions = [| 1/1; 1/2; ;2/3 3/4; 4/6; 4/8; 6/10; 7/11; 7/12; 8/13; 8/14 |]
    *)

我需要通过迭代第三个数组生成一个新的集合,其中包括没有计数" &LT = "它的每个价值观。最后,我需要遍历这个新集合,以创建一个新列,其中包含每个值的比例,并打印每个唯一值及其匹配的比例。

请指教?

1 个答案:

答案 0 :(得分:6)

首先,使用一些更有意义的名称:

let nums  = [| 25; 20; 23; 10; 8; 5; 4; 12; 19; 15; 15; 12; 11; 11 |]
let yesNos = // convert string -> bool to simplify following code
  [| "No"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No" |]
  |> Array.map (fun s -> s = "Yes")
let distinctNums = nums |> Array.distinct |> Array.sort
let numYesNos = Array.zip nums yesNos

然后,如果你真的想要为每个是/否/比率计算单独收集,你可以使用折叠构建那些:

let foldYesNos num (yesCounts, noCounts, yesRatios) =
  // filter yes/no array by <= comparison
  // then partition it into two arrays by the second bool item
  let (yays, nays) = numYesNos |> Array.filter (fun (n,_) -> n <= num) |> Array.partition snd
  let yesCount = Array.length yays
  let noCount = Array.length nays
  let yesRatio = float yesCount / float(yesCount + noCount)
  (yesCount::yesCounts, noCount::noCounts, yesRatio::yesRatios)

// fold *back* over the distinct numbers
// to make the list accumulation easier/not require a reversal
let (yays, nays, ratio) = Seq.foldBack foldYesNos (distinctNums |> Seq.sort) ([], [], [])

但是,我假设您在样本中发布了Collective记录类型,您可能实际上想要为每个输入发出以下记录之一:

type Collective = { score:int; yes:int; no:int; correct:float }

let scoreNum num =
  let (yays, nays) = numYesNos |> Array.filter (fun (n,_) -> n <= num) |> Array.partition snd
  let yesCount = Array.length yays
  let noCount = Array.length nays
  let yesRatio = float yesCount / float(yesCount + noCount)
  { score = num; yes = yesCount; no = noCount; correct = yesRatio }

distinctNums |> Array.map scoreNum

您可以看到此代码非常相似,它只返回每个输入的Collective记录,而不是为单个计算构建列表,因此我们可以使用 map 而不是a fold