如何获取序列中所有组的开始和结束索引

时间:2013-12-03 02:59:11

标签: f# functional-programming

我有一组bools分组如下:

[|true; false; true; true; true; false; true; false; true; true; true; false;
true; true; false; true; true; true; false; true|]

我想要的是得到所有连续真实组的索引:

[|(0, 0); (2, 4); (6, 6); (8, 10); (12, 13); (15, 17); (19, 19)|]

我的功能解决方案是:

let getBlocksIndices (r:bool[]) =
    let f = Array.append r [|false|]
    Seq.unfold(fun (p,i) ->
                    let nSt = f.[i],i+1
                    match p,f.[i] with
                    | false,true -> Some (i,nSt)
                    | true,false -> Some (i-1,nSt)
                    | _ -> Some (-1,nSt)

              ) (false,0)
    |> Seq.take f.Length
    |> Seq.filter (fun e -> e>=0 )
    |> Seq.pairwise
    |> Seq.mapi (fun i x -> if i%2=0 then Some(x) else None)
    |> Seq.choose id
    |> Array.ofSeq

但我认为这对于这么简单的任务来说太大了,

你有更简单的选择吗?

2 个答案:

答案 0 :(得分:2)

最简单的方法 - 将其转换为列表并使用递归。通过这种方式,您可以在列表中单次传递

let rec blocklist l prevtrue idx =
    match l,prevtrue with
    |true ::t,None       ->               blocklist t (Some idx) (idx+1)
    |true ::t,ptrue      ->               blocklist t ptrue      (idx+1)
    |false::t,None       ->               blocklist t None       (idx+1)  
    |false::t,Some(sval) -> (sval,idx-1)::blocklist t None       (idx+1)
    |[],Some(t)          -> (t,idx-1)::[]
    |[],_                -> []

let blockify a = a |> Array.toList |> fun f -> blocklist f None 0

> blockify [|true; false; true; true; true; false; true; false; true; true; true; false;
- true; true; false; true; true; true; false; true|];;                                  
val it : (int * int) list =
  [(0, 0); (2, 4); (6, 6); (8, 10); (12, 13); (15, 17); (19, 19)]

答案 1 :(得分:0)

另一种方法 - 将布尔值映射到数组索引,使用group by进行分组并最终计算范围。

let grouped booleans = 
    booleans
    |> Seq.mapi (fun idx x -> if x then idx else -1)        // if true map to index else -1
    |> Seq.scan
            (fun prevIdx idx -> 
                match (prevIdx, idx) with                   // match current index with previous index
                |   _, -1       ->  -1
                |   -1, _       ->  idx
                |   _           ->  prevIdx)                
            -1
    |> Seq.groupBy id                                       // group by the repeating key
    |> Seq.filter (fun (key, group) -> key <> -1)           // remove the 'false group'   
    |> Seq.map (fun (key, group) -> (key, (group |> Seq.length) + key - 1)) // compute range