Eh bien, vous pouvez le rendre récursif, mais vous devez inverser la liste. Vous ne voudriez pas le plier car il peut sortir de la boucle récursive à tout moment. J'ai fait un peu de test et l'inversion de la liste est plus que compensée par la récursivité de la queue.
// 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)
Une version similaire à celle de Brian qui est récursive en queue et prend un seul prédicat de valeur.
// 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)
Ceci est différent de la partition de fonction de bibliothèque en ce qu'elle arrête de prendre des éléments dès que le prédicat retourne faux peu comme Seq.takeWhile.
// 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]
Pouvez-vous préciser ce que pred fait? Si cela nécessite de vérifier tous les éléments ensemble et pas un par un, il n'y a aucun moyen de contourner O (n^2). – gradbot
Essayez-vous de diviser la liste en deux lorsque vous arrivez à la première valeur qui renvoie true à partir de votre prédicat? – gradbot
Oui, vous avez raison O (n^2) est le meilleur pour cette situation. A propos de predicate: il s'agit du point de partage, lorsque le prédicat renvoie false. Mais ce n'est pas si important car il est facile d'inverser le résultat du prédicat. –