有没有" List.divideAt" HOF在F#库中?

时间:2015-10-13 22:20:19

标签: .net f# functional-programming

我实现了一个我选择调用divideAt的函数:

module List =
    let divideAt predicate list =
        let rec divideAt' acc = function
            | [] -> (List.rev acc, [])
            | h::_ as ls when predicate h -> (List.rev acc, ls)
            | h::t -> divideAt' (h::acc) t
        divideAt' [] list

这个想法相对简单:有时你想给定一个列表中的元素,将它之前的所有元素分成左边的列表,然后将所有元素分成另一个元素。

我查看了List的所有功能,但我无法找到任何可以让我以高效的方式执行此操作的功能。还是有吗?完全依赖于高阶函数的等效但速度较慢的实现可以通过这种方式实现,例如:

let divideAt predicate list =
    match List.tryFindIndex predicate list with
    | None -> (list, [])
    | Some(index) -> (List.take index list, List.skip index list)

是否有一些东西可以让我更简洁地实现这一点,而不必依赖"低水平"在使用这个HOF实现时,没有性能损失的递归算法?

谢谢

2 个答案:

答案 0 :(得分:6)

我能想到的唯一变化是使用已经处理的List.splitAt,取/跳部分(可能更好):

let divideAt predicate list =
  match List.tryFindIndex predicate list with
    None       -> list, []
  | Some index -> List.splitAt index list

另外,这是另一种相同的语法;我不认为函数调用和匹配表达式之间应该存在性能差异,但是以下情况:

let divideAt predicate list =
  List.tryFindIndex predicate list
  |> Option.map (List.splitAt >> (|>) list)
  |> defaultArg <| (list, [])

答案 1 :(得分:2)

使用List.partition

可以非常有效地完成此操作
let divideAt predicate ll =
    let split = ref false
    let splitter predicate x =
        split := !split || (predicate x); !split

    ll |> List.partition (splitter predicate)

并使用它,如下例所示:

> divideAt ((=) 7) [1; 8; 2; 7; 3; 6]
val it : int list * int list = ([7; 3; 6], [1; 8; 2])