【发布时间】:2015-11-07 05:24:54
【问题描述】:
我在 Erlang 中有一个元素列表,我正在使用 lists:foreach 遍历列表中的元素。有没有办法在遍历中间打破这个“foreach 循环”。例如:假设如果我在列表 [2, 4, 5, 1, 2, 5] 中遇到“1”,我想停止进一步遍历列表。我该怎么做?
【问题讨论】:
我在 Erlang 中有一个元素列表,我正在使用 lists:foreach 遍历列表中的元素。有没有办法在遍历中间打破这个“foreach 循环”。例如:假设如果我在列表 [2, 4, 5, 1, 2, 5] 中遇到“1”,我想停止进一步遍历列表。我该怎么做?
【问题讨论】:
另一种方法是使用throw 和catch:
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 本身也不例外。它应该用于流量控制。请参考 Erlang 的参考指南
traverse(Liste) ->
traverse(Liste, []).
traverse([], Acc) ->
Acc;
traverse([1|_], Acc) ->
Acc;
traverse([H|T], Acc) ->
% do something useful here maybe?
traverse(T, Acc).
当然这是非常粗略的例子。
【讨论】:
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)
【讨论】:
我遇到同样的问题,就这样解决了:
-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]
【讨论】:
列表:全部?
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 中返回结果,就会爆发。
【讨论】: