这里有另一种使用内置库函数的方法来完成它,这可能比其他答案更易于理解。此解决方案还仅需要对输入进行一次遍历。看完你的问题后,我首先想到的是你想要类似于List.partition的东西,它可以根据给定的谓词将列表分成两个列表。然而,在你的情况下,这个谓词将基于当前元素的索引,而partition无法处理,除非查找每个元素的索引。
我们可以使用fold或foldBack来实现创建我们自己等效于此行为的方式。我将在此处使用foldBack,因为这意味着您无需在之后反转列表(请参见Stephens的优秀答案)。我们要做的是使用fold提供我们自己的索引以及两个输出列表,所有内容都作为累加器。以下是将根据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.
所以在这里,我们使用 ([],[],0) 作为初始累加器值开始 foldBack。然而,因为我们是从列表末尾开始的,所以需要将表示当前索引的 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
我希望能在IT技术方面为您提供一些帮助!
> 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.