Если вы покажете, что вы пробовали, то мы сможем помочь вам в том конкретном моменте, в котором вы застряли.
Также попробуйте обобщить вашу проблему, чтобы найти возможные подходы, которые имеютмне уже предлагали, например «У меня есть частично отсортированный список, и я хочу разделить его по предикату, сравнивая два смежных значения».Это, возможно, привело вас к существующим ответам, например, F # Как отобразить последовательность на основе предиката, а не фиксированной длины
Если они не соответствуют вашим требованиям, попробуйте этот,Это вложенная рекурсивная функция с аккумулятором и аргументом, объединенными в кортеж, где после использования всех аргументов аккумулятор и его подсписки нуждаются в обращении.
let splitWhen p xs =
let rec aux = function
| ((y::_)::_) as yss, x::xs when p x y -> aux ([x]::yss, xs)
| ys::yss, x::xs -> aux ((x::ys)::yss, xs)
| [], x::xs -> aux ([[x]], xs)
| yss, [] -> List.rev <| List.map List.rev yss
aux ([], xs)
splitWhen (<) [1;2;3;3;4]
// val it : int list list = [[1; 2; 3; 3; 4]]
splitWhen (<) [1;2;3;2;4;3;5]
// val it : int list list = [[1; 2; 3]; [2; 4]; [3; 5]]
Редактировать
Хорошо, давайте сделаем шаг назад.Рекурсивная функция должна быть tail recursive , то есть вы не должны иметь незаконченного бизнеса при рекурсивном вызове функции;это может переполнить стек.Это, в свою очередь, требует дополнительного аргумента для накопления промежуточных значений, которые вы вычислили до сих пор, который обычно называется аккумулятором.
В то же время, аккумулятор является удобным местом для поиска предыдущего значения, чтобысравните это с текущим.За исключением случаев, когда аккумулятор пуст - вот почему нам нужно сопоставить как аккумулятор, так и аргументы, чтобы обрабатывать особые случаи, когда один из них пуст.
Легко увидеть, как тест предикатов можетбыть учтены, что приведет к версии выше.
let rec splitList<'T when 'T: comparison> (acc : 'T list list) (list: 'T list) : 'T list list =
match acc, list with
| (y::_) as ys::yss, x::xs ->
if x >= y then splitList ((x::ys)::yss) xs
else splitList ([x]::acc) xs
| _, x::xs -> splitList [[x]] xs
| _ -> List.rev (List.map List.rev acc)
splitList [] [1;2;3;3;4]
// val it : int list list = [[1; 2; 3; 3; 4]]
splitList [] [1;2;3;2;4;3;5]
// val it : int list list = [[1; 2; 3]; [2; 4]; [3; 5]]
Edit2
Вы также можете использовать не аккумулятор, а понимание списка (он же список выражение последовательности ) вместо этого.Это своего рода обман, так как для этого нужна вспомогательная функция, которая использует аккумулятор;он выдаст подпись val splitList : list:'a list -> 'a list list when 'a : comparison
.
let rec partitionWhile p = function
| x::xs, y::ys when p x y -> partitionWhile p (y::x::xs, ys)
| xss, yss -> List.rev xss, yss
let rec splitList list = [
if not <| List.isEmpty list then
let acc, rest = partitionWhile (<=) ([list.Head], list.Tail)
if not <| List.isEmpty acc then
yield acc
yield! splitList rest ]
splitList [1;2;3;3;4]
// val it : int list list = [[1; 2; 3; 3; 4]]
splitList [1;2;3;2;4;3;5]
// val it : int list list = [[1; 2; 3]; [2; 4]; [3; 5]]