F# - 将列表按奇偶元素拆分为元组(按元素而非位置)

3

示例:split [1;3;2;4;7;9];;
输出:([1;3;7;9], [2;4])

我是 F# 新手,无法理解。
不能使用内置的 partition 函数。

这是我目前的代码:

let rec split xs = 
    match xs with
    | [] -> [], []
    | xs -> xs, []
    | xh::xt -> let odds, evens = split xt
                if (xh % 2) = 0 then xh::odds, xh::evens
                else xh::odds, evens  

修复后的代码:

let rec split xs = 
    match xs with
    | [] -> [], []
    | xh::xt -> let odds, evens = split xt
                if (xh % 2) = 0 then odds, xh::evens
                else xh::odds, evens

*感谢@TheInnerLight指出我的错误:无法到达的情况和不必要地修改几率


1
一个忠告,因为这似乎是一道作业:你应该告诉你的教授你在 Stack Overflow 上寻求了帮助,并告知他们得到了什么样的帮助。最好的方法就是在你提交作业时,在评论中包含这个问题的链接: https://dev59.com/5aLia4cB1Zd3GeqPhVb8/。根据你的教授对寻求帮助的政策,你可能需要或不需要这样做,但完全透明地披露任何在完成作业时得到的帮助总是一个好主意。 - rmunn
感谢您编辑问题以帮助未来可能遇到类似问题的其他人。但是,在Stack Overflow上,没有必要在问题标题中加入“(已解决)”:您通过给出绿色复选标记接受答案的事实足以传达这一事实,事实上,人们更喜欢在问题标题中不加入“(已解决)”。尽管如此,我们非常感激您的愿意这样做。 :-) - rmunn
1个回答

8

您可以使用内置的 List.partition 函数。

let splitOddEven xs =
    xs |> List.partition (fun x -> x % 2 <> 0)
splitOddEven [1;3;2;4;7;9];;
val it : int list * int list = ([1; 3; 7; 9], [2; 4])
如果你想要一个递归实现,我会选择一个尾递归的实现方式,像这样:
let splitOddEven xs =
    let rec splitOddEvenRec oddAcc evenAcc xs = 
        match xs with
        | [] -> oddAcc, evenAcc
        | xh::xt -> 
            if (xh % 2) = 0 then splitOddEvenRec oddAcc (xh :: evenAcc) xt
            else splitOddEvenRec (xh :: oddAcc) evenAcc xt
    splitOddEvenRec [] [] xs

splitOddEven  [1;3;2;4;7;9]

请注意,这将以相反的顺序为您生成两个结果列表,因此您可能希望自行颠倒它们。

这正好符合我的要求。但是我不能使用List.partition函数来解决这个问题。我会研究一下该函数的工作原理并尝试解决这个问题。非常感谢! - Sergio Rosales
@SergioRosales 刚刚也添加了一个递归实现。 - TheInnerLight
@SergioRosales 没问题。顺便说一下,你在问题中提供的实现几乎可以工作。如果删除| xs -> xs,[]模式匹配案例并将if(xh%2)= 0 then xh :: odds,xh :: evens替换为if(xh%2)= 0 then odds,xh :: evens,则有另一个可行的实现。但是,该实现不是尾递归的,因为进行递归调用不是函数执行的最后一件事。这就是为什么我想向您展示不同的东西的原因。 - TheInnerLight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接