【问题标题】:Erlang : Breaking out of lists:foreach "loop"Erlang:打破列表:foreach“循环”
【发布时间】:2015-11-07 05:24:54
【问题描述】:

我在 Erlang 中有一个元素列表,我正在使用 lists:foreach 遍历列表中的元素。有没有办法在遍历中间打破这个“foreach 循环”。例如:假设如果我在列表 [2, 4, 5, 1, 2, 5] 中遇到“1”,我想停止进一步遍历列表。我该怎么做?

【问题讨论】:

    标签: erlang foreach


    【解决方案1】:

    另一种方法是使用throwcatch

    catch lists:foreach(
            fun(1) ->
                    throw(found_one);
               (X) ->
                    io:format("~p~n", [X])
            end,
            [2, 4, 5, 1, 2, 5]).
    

    在 shell 中运行时,输出:

    2
    4
    5
    found_one
    

    编辑:根据大众的需求,一个更精确的版本,只捕捉你想捕捉的东西:

    try lists:foreach(
            fun(1) ->
                    throw(found_one);
               (X) ->
                    io:format("~p~n", [X])
            end,
            [2, 4, 5, 1, 2, 5])
    catch
        throw:found_one ->
            found_one
    end.
    

    【讨论】:

    • 使用异常抛出应该是函数的“非本地返回”。此答案中的用法是有效的 throw 用法,我不明白为什么它当时被否决。
    • 在 Python 社区中有一种说法“这个解决方案不是很 Pythonic ”。 Erlang 社区中是否有等价的表达方式? ;-)
    • Exceptions 应该用于表示异常情况,而不是用于流量控制
    • throw 本身也不例外。它应该用于流量控制。请参考 Erlang 的参考指南
    • 如何处理“意外”异常?在这个简单的例子中,如果 io:format 抛出一些东西,你会怎么做?你必须为“这种投掷”和“那种投掷”做好准备。把这个改写成case catch,或者try catch,就不会这么简单了……
    【解决方案2】:
    traverse(Liste) ->
     traverse(Liste, []).
    
    traverse([], Acc) ->
     Acc;    
    
    traverse([1|_], Acc) ->
     Acc;
    
    traverse([H|T], Acc) ->
     % do something useful here maybe?
     traverse(T, Acc).
    

    当然这是非常粗略的例子。

    【讨论】:

    • 是的,我经常发现更容易理解类似 lists:foreach 的工作原理,然后编写自己的版本来满足特殊情况。正如您在上面看到的,代码行数是微不足道的。浏览列表模块的源代码将深入了解 Erlang 语言及其使用...
    • 我的观点也是:一旦你熟悉了 Erlang,这种表现力就会产生奇迹。
    • 我想知道这是否会返回除 [] 以外的任何内容(不包括没有匹配的函数子句:o))
    • @zed:当然,这取决于您在“可能在这里做一些有用的事情”部分中的内容。 “Acc”用作“累加器”。快点 Zed,已经很晚了 ;-)
    • 很好的解决方案,但我花了一些时间才理解。如果您不了解 Erlang 函数重载,请务必查看 erlang.org/doc/reference_manual/functions.html
    【解决方案3】:

    lists 模块中有很多不错的功能:

    lists:foreach(fun(E) -> do_something(E) end,
        lists:takewhile(fun(E) -> E =/= 1 end, List)).
    

    或更有效但不太好

    lists:takewhile(fun(1) -> false;
                       (E) -> do_something(E), true
                    end, List)
    

    【讨论】:

    【解决方案4】:

    我遇到同样的问题,就这样解决了:

    -module(foreach_until).
    -export([foreach_until/3]).
    
    foreach_until(Action, L, Judge)     ->
        lists:reverse(foreach_until(Action, L, Judge, []))
        .
    
    foreach_until(_, [], _, Result) ->
        Result
        ;
    
    foreach_until(Action, [H | T], Judge, Result)   ->
        case Judge(H) of 
            true    -> Result;
            false   -> foreach_until(Action, T, Judge, [Action(H) | Result])
        end
        .
    

    下面是一个例子说明如何使用:

    60> foreach_until:foreach_until(fun(X) -> X*X end, [1,2,3,4], fun(X)-> X >= 3 end).
    [1,4]
    

    【讨论】:

      【解决方案5】:

      列表:全部?

      do_something(A) ->
         case A of 
            1 ->
               false;
            _ ->
               true
         end.
      
      IsCompleted = lists:all(do_something(A), [2, 4, 5, 1, 2, 5]),
      

      只要 do_something 返回 false 并在 IsCompleted 中返回结果,就会爆发。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-08
        • 2014-03-24
        • 2018-07-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多