Вот еще один способ сделать это, используя встроенные библиотечные функции, которые могут быть или не быть проще для понимания, чем некоторые другие ответы. Это решение также требует только одного обхода ввода. После того, как я посмотрел на вашу проблему, моей первой мыслью было то, что вы хотите что-то вроде List.partition, которая разбивает список на два списка на основе заданного предиката. Однако в вашем случае этот предикат будет основан на индексе текущего элемента, который раздел не может обработать, если не считать поиск индекса для каждого элемента.
Мы можем создать собственный эквивалент этого поведения, используя fold или foldBack. Здесь я буду использовать foldBack, так как это означает, что вам не нужно будет переворачивать списки позже (см. Отличный ответ Стивенса). То, что мы собираемся сделать здесь, это использовать складку, чтобы предоставить наш собственный индекс, а также два списка вывода, все в качестве аккумулятора. Вот общая функция, которая разделит ваш список на два списка на основе индекса n:
let gencut n input =
//calculate the length of the list first so we can work out the index
let inputLength = input |> List.length
let results =
List.foldBack( fun elem acc->
let a,b,index = acc //decompose accumulator
if (inputLength - index) <= n then (elem::a,b,index+1)
else (a,elem::b,index+1) ) input ([],[],0)
let a,b,c = results
(a,b) //dump the index, leaving the two lists as output.
Итак, вы видите, что мы запускаем foldBack с начальным значением аккумулятора ([], [], 0). Однако, поскольку мы начинаем с конца списка, 0, представляющий текущий индекс, необходимо вычесть из общей длины списка, чтобы получить фактический индекс текущего элемента.
Затем мы просто проверяем, находится ли текущий индекс в диапазоне n. Если это так, мы обновляем аккумулятор, добавляя текущий элемент в список a, оставляя список b в покое, и увеличиваем индекс на 1: (elem :: a, b, index + 1). Во всех остальных случаях мы делаем то же самое, но вместо этого добавляем элемент в список b: (a, elem :: b, index + 1).
Теперь вы можете легко создать свою функцию, которая разделяет список пополам, создавая другую функцию, например:
let cut input =
let half = (input |> List.length) / 2
input |> gencut half
Надеюсь, это может вам чем-то помочь!
> cut data;;
val it : int list * int list = ([1; 2; 3], [4; 5; 6])
> gencut 5 data;;
val it : int list * int list = ([1; 2; 3; 4; 5], [6])
РЕДАКТИРОВАТЬ: вы можете избежать отрицания индекса, указав длину в качестве начального значения аккумулятора и отрицая ее в каждом цикле, вместо того, чтобы увеличивать ее - возможно, проще так:)
let gencut n input =
let results =
List.foldBack( fun elem acc->
let a,b,index = acc //decompose accumulator
if index <= n then (elem::a,b,index-1)
else (a,elem::b,index-1) ) input ([],[],List.length input)
let a,b,c = results
(a,b) //dump the index, leaving the two lists as output.