Optimization 如何在F#more中优化拆分?

Optimization 如何在F#more中优化拆分?,optimization,f#,simplification,Optimization,F#,Simplification,这段代码使用一个谓词将列表拆分为两部分,该谓词获取列表并在拆分时返回false let split pred ys = let rec split' l r = match r with | [] -> [] | x::xs -> if pred (x::l) then x::(split' (x::l) xs) else [] let res = split' [] ys let last = ys |>

这段代码使用一个谓词将列表拆分为两部分,该谓词获取列表并在拆分时返回false

let split pred ys =
    let rec split' l r = 
        match r with
        | [] -> []
        | x::xs -> if pred (x::l) then x::(split' (x::l) xs) else []
    let res = split' [] ys
    let last = ys |> Seq.skip (Seq.length res) |> Seq.toList
    (res, last)

有人知道在F#中实现这一点的更优化和更简单的方法吗?

好吧,你可以让它尾部递归,但你必须颠倒列表。您不希望折叠它,因为它可以随时退出递归循环。我做了一些测试,反转列表不仅仅是尾部递归所弥补的

// val pred : ('a list -> bool)
let split pred xs =
    let rec split' l xs ys = 
        match xs with
        | [] -> [], ys
        | x::xs -> if pred (x::l) then (split' (x::l) xs (x::ys)) else x::xs, ys 
    let last, res = split' [] xs []
    (res |> List.rev, last)
一个类似于Brian的版本,是尾部递归的,并采用单值谓词

// val pred : ('a -> bool)
let split pred xs =
    let rec split' xs ys =
        match xs with
        | [] -> [], ys
        | x::xs -> if pred x then (split' xs (x::ys)) else (x::xs), ys
    let last, res = split' xs []
    (res |> List.rev, last)
这与库函数分区不同,它在谓词返回类似于Seq.takeWhile的false时停止获取元素

// library function
let x, y = List.partition (fun x -> x < 5) li
printfn "%A" x  // [1; 3; 2; 4]
printfn "%A" y  // [5; 7; 6; 8]

let x, y = split (fun x -> x < 5) li
printfn "%A" x  // [1; 3]
printfn "%A" y  // [5; 7; 2; 4; 6; 8]
//库函数
设x,y=List.partition(funx->x<5)li
printfn“%A”x/[1;3;2;4]
printfn“%A”y/[5;7;6;8]
设x,y=split(funx->x<5)li
printfn“%A”x/[1;3]
printfn“%A”y/[5;7;2;4;6;8]

不是尾部递归,而是:

let rec Break pred list =
    match list with
    | [] -> [],[]
    | x::xs when pred x -> 
        let a,b = Break pred xs
        x::a, b
    | x::xs -> [x], xs

let li = [1; 3; 5; 7; 2; 4; 6; 8]
let a, b = Break (fun x -> x < 5) li    
printfn "%A" a  // [1; 3; 5]
printfn "%A" b  // [7; 2; 4; 6; 8]

// Also note this library function
let x, y = List.partition (fun x -> x < 5) li
printfn "%A" x  // [1; 3; 2; 4]
printfn "%A" y  // [5; 7; 6; 8]
让rec中断pred列表=
匹配列表
| [] -> [],[]
|x::当pred x->
设a,b=中断pred xs
x::a,b
|x::xs->[x],xs
设li=[1;3;5;7;2;4;6;8]
让a,b=休息(乐趣x->x<5)li
printfn“%A”A/[1;3;5]
printfn“%A”b/[7;2;4;6;8]
//还要注意这个库函数
设x,y=List.partition(funx->x<5)li
printfn“%A”x/[1;3;2;4]
printfn“%A”y/[5;7;6;8]

以下是一些方法:

let split' pred xs = let f (ls,rs,cond) x = if cond (ls@[x]) then (ls@[x],rs,cond) else (ls,rs@[x],(fun _->false))
                     let ls,rs,_ = List.fold f ([],[],pred) xs
                     ls, rs

你能详细说明pred的工作吗?如果它需要将所有元素一起检查,而不是逐个检查,则无法绕过O(n^2)。当从谓词中得到第一个返回true的值时,是否尝试将列表一分为二?是的,O(n^2)最适合这种情况。关于谓词-当谓词返回false时,它是分割点。但这并不重要,因为它很容易反转谓词的结果。耶,我不知道他是想用谓词逐块测试列表,还是一个接一个地测试列表。必须保留输入顺序,谓词应该采用[1..10]>[1]、[1;2]、[1;2;3]等的列表。takeWhile具有谓词('a->bool),但我确实需要('a list->bool)作为谓语。输入顺序也应该保留。可能这个“Seq.skip”可以被跳过并直接导出右侧结果。我将进一步考虑。我从第一个代码示例中删除了Seq.skip。它与第二个示例类似,但仍然使用pred:('a list->bool)谢谢!你的解决方案是最好的!