【问题标题】:How to stop the traversal of a list如何停止遍历列表
【发布时间】:2021-02-12 08:07:15
【问题描述】:

我从 Fsharp 开始,我有这个问题。 假设我有两个长度相同的列表 a 和 b,我同时遍历这些列表,并在每一步测试 a 和 b 的条件,并使用先前的微积分的结果。如果此测试失败,则无需继续。 我写了这段代码:

let mutable (i : int) = 0
let mutable (good : bool) = true
let mutable (previous : int) = 0
while good && i < len do
    good <- test a.[i] b.[i] previous
    previous <- my_func a.[i] b.[i]
    i <- i + 1

我看到这段代码要好得多:

List.zip a b |> List.fold (fun (x, y) (a,b) -> (p && test a b y, my_func a b) (true, 0)

但是,对于我的代码,一旦测试失败,过程就完成了,而不是第二个代码。 有没有办法,使用第二个代码的设计来停止进程?

谢谢

【问题讨论】:

    标签: f#


    【解决方案1】:

    我假设您只对最终结果是否为good 感兴趣。

    正如 Brian 所说,您可以使用 Seq.scan,其行为类似于 Seq.fold,但它返回所有中间状态,而不仅仅是最终状态。通过使用Seq 而不是List,您还使用了惰性序列,因此函数可以提前终止。做你想做的事,你可以使用Seq.scanSeq.forall,这将检查给定序列的所有值是否满足特定条件——这里的好处是,只要条件为@,它就可以提前终止987654328@.

    把所有这些放在一起,我得到了这样的东西:

    Seq.zip a b 
    |> Seq.scan (fun (good, prev) (a, b) -> 
         test a b prev, my_func a b) (true, 0)
    |> Seq.forall (fun (good, _) -> good)
    

    【讨论】:

    • 我喜欢这个,结果比我预期的要简单。您甚至可以将最后一行简化为 |&gt; Seq.forall fst
    【解决方案2】:

    三个想法:

    • 您可以编写自己的 fold 变体,当标志设置为 false 时停止。不过,就我个人而言,我认为这会很麻烦。

    • 您可以使用Seq.scan 懒惰地累积my_func 的所有结果,然后检查它们,类似于this answer。由于Seq 是懒惰的,因此扫描会以您想要的方式短路。不过,这很难做到。

    • 您可以递归地遍历列表。恕我直言,这是最简单的功能解决方案。像这样的:

    let rec examine listA listB prev =
        match listA, listB with
            | headA :: tailA, headB :: tailB ->
                if test headA headB prev then
                    let prev' = my_func headA headB
                    examine tailA tailB prev'
                else false
            | [], [] -> true
            | _ -> false
    examine listA listB 0
    

    【讨论】:

    • 感谢您的回答和链接。基本上你的代码和我自己的代码有相同的设计,但是更优雅!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 2019-02-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多