F#查找3元组的合格的最后一个元组

时间:2011-12-09 20:23:08

标签: f#

let dataA3 = [| ("A", 1.0M, -2.0M); 
                ("A", 2.0M, -1.8M);
                ("A", 3.0M, -1.5M);
                ("B", 2.0M, -1.5M);
                ("B", 3.0M, -1.8M);
                ("C", 1.0M, 2.0M); 
                ("C", 2.0M, 1.8M);
                ("C", 3.0M, 1.5M) |]

我有一系列元组,我会找到合格的元组。条件是:

  1. 第一个字符串元素必须相同3次,在上例中,(“A”,_,_)和(“C”,_,_)是合格的,但是(“B” ,_,_)不是,因为只有2个元组包含“B”;如果相同的第一个元素的数量出现超过3次,则它们也不合格。

  2. 第二个小数元素必须按升序排列且大于0.0M;

  3. 第三个小数元素必须按升序排列,但可以小于0.0M; 例如:(“A”,1.0M,-2.0M); (“A”,2.0M,-1.8M); (“A”,3.0M,-1.5M)符合此条件;但是(“C”,1.0M,2.0M); (“C”,2.0M,1.8M); (“C”,3.0M,1.5M)不符合此条件,因为2.0M - > 1.8M - > 1.5M按降序排列,而不是按升序排列。

  4. 最后,我想获得符合条件的3元组的最后一个元组。在上面的例子中,我想最终的元组是(“A”,3.0M,-1.5M)

    let final = [| ("A", 3.0M, -1.5M) |]
    

    如果有更多元组符合条件,我只需要每个不同的第一个字符串元素的3个元组中的最后一个元组。 谢谢,

4 个答案:

答案 0 :(得分:4)

对于练习,我从BLUEPIXY的代码中删除了大多数自定义fun定义。 Seq.reduce也是获取序列中最后一个值的好方法。理解这段代码是好的,不要把它写在生产中。

let tpl3_1 (x,_,_) = x
let tpl3_2 (_,x,_) = x
let tpl3_3 (_,_,x) = x

let isAscendingBy f =
    Seq.map f
    >> Seq.pairwise
    >> Seq.forall ((<||) (<=))

let filter1 =
    Seq.groupBy tpl3_1 
    >> Seq.filter (snd >> Seq.length >> (=) 3)
    >> Seq.map snd 

let filter2 =
    Seq.filter (Seq.forall (tpl3_2 >> (<) 0.0m))
    >> Seq.filter (isAscendingBy tpl3_2)

let filter3 =
    Seq.filter (isAscendingBy tpl3_3)

let choiceLast =
    Seq.reduce (fun _ x -> x)

let final =
    filter1 
    >> filter2 
    >> filter3 
    >> Seq.map choiceLast

dataA3 |> final |> printfn "%A"

答案 1 :(得分:3)

let isAscendingBy f sq =
  sq
  |> Seq.map f
  |> Seq.pairwise
  |> Seq.forall (fun (x1,x2) -> x1 <= x2)

let filter1 x =
  x 
  |> Seq.groupBy (fun (a,_,_) -> a) 
  |> Seq.filter (fun (_, g) -> Seq.length g = 3) // than more ? >=
  |> Seq.map snd 

let filter2 x =
  x
  |> Seq.filter (fun x -> Seq.forall (fun (_,b,_) -> b >= 0.0m) x)
  |> Seq.filter (isAscendingBy (fun (_,b,_) -> b))

let filter3 x =
  x
  |> Seq.filter (isAscendingBy (fun (_,_,c) -> c))

let choiceLast x =
  (x |> Seq.toArray |> Array.rev).[0]

let final = dataA3 |> filter1 |> filter2 |>filter3 |> Seq.toArray |> Array.map choiceLast

答案 2 :(得分:2)

dataA3
|> Seq.groupBy (fun (a,_,_) -> a)
|> Seq.filter (fun (_, d) -> 
  (d |> Seq.sumBy (fun (_,b,_) -> b)) > 0M
    && (d |> Seq.pairwise |> Seq.forall (fun ((_,x0,x1), (_,y0,y1)) -> x0 < y0 && x1 < y1)))
|> Seq.map (fun (_, d) -> d |> Seq.reduce (fun _ x -> x))
|> Seq.toArray

输出

[|("A", 3.0M, -1.5M)|]

答案 3 :(得分:1)

另一个答案

open System.Collections.Generic
let selectData sq =
  let dic  = new Dictionary<string, string * decimal * decimal>()
  let dicc = new Dictionary<string, int>() //counter
  for (key, v1, v2) as v in sq do
    if dicc.ContainsKey key then
      let (_, oldV1, oldV2) = dic.[key]
      if v1 > 0.0M && oldV1 <= v1 && oldV2 <= v2 then
        dicc.[key] <- dicc.[key] + 1
        dic.[key] <- v //replace new value
    elif v1 > 0.0M then
      dic.Add(key, v)
      dicc.Add(key, 1)
  for x in dicc do
    if x.Value < 3 then dic.Remove(x.Key) |> ignore
  dic.Values |> Seq.toArray

let final = selectData dataA3