首页 > 解决方案 > 如何打破对 FSharp 中列表的迭代?

问题描述

当第一项匹配条件时,我想停止迭代列表。

let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
let list2 = [1; 2; 9]
list1 |> List.iter (fun item ->
        match List.contains item list2 with
        | false -> printfn " Not Present %A" item
        | true -> printfn "%A" item)

我只想打印此处不存在的第一个项目,在这种情况下为 3。在功能性地编写代码时如何做到这一点?

标签: loopsf#break

解决方案


函数世界中迭代的最终基础是递归:你的函数计算一些东西,然后调用自己进行下一步。或者它决定停止,然后它调用自己。简单的。

您的特殊情况非常适合这种范式:

let rec loop list = 
    match list with
    | [] -> () // no more list - just return
    | head::tail ->
        if List.contains head list2
            then loop tail // deciding to call myself
            else printfn " Not Present %A" head // deciding not to call myself

loop list1  // Kick off the process

但是呢iter?好吧,模块中的所有这些花哨的功能List——包括iter——都建立在相同的递归方案之上。他们也决定是否在每一步都打电话给自己。对于其中一些,您可以通过参数影响决策,而对于另一些则不能。

碰巧iter你不能。iter将始终调用自己进行下一步,因此它将始终遍历整个列表。你无能为力。

但是还有其他功能可以影响是否递归的决定。其中有很多,但对于您的目的,我认为List.tryFind最适合。它接受另一个函数作为参数,它应该返回truefalse。如果返回truetryFind将停止迭代并返回当前元素。正是你需要的。

list1 |> List.tryFind (fun x -> 
  if List.contains x list2
    then false
    else printfn " Not Present %A"; true
)

推荐阅读