设计模式?函数遍历列表以搜索第一个{success}结果

时间:2010-07-19 23:59:00

标签: erlang

我在Erlang中遇到了编码问题,这可能是一种常见的设计模式,但我找不到任何有关如何解决它的信息。

我有一个列表L.我想将函数f应用于L中的每个元素,并让它同时运行在L中的所有元素中。每次调用f(元素)都会成功或失败;在大多数情况下,它会失败,但偶尔它会成功获得L内的特定元素。

如果/当af(元素)成功,我想返回“成功”终止对L中其他元素的f的所有调用 - 第一个“成功”是我感兴趣的全部另一方面,如果f(Element)对L中的每个元素都失败,那么我想返回“fail”。

作为一个简单的例子,假设L是一个整数列表,如果L中的元素是3,则F返回{success},或者对于任何其他值,则返回{fail}。如果L中有3个,我希望尽快找到;我不在乎有多少3s,只是至少有3个存在与否。 f可能看起来像这样:

f(Int) ->
  case Int of
    3 -> {success};
    _ -> {fail}
  end.

如何遍历Int列表以查明列表是否包含至少一个3,并尽快返回?

当然这是一种常见的功能设计模式,我只是没有在Google中使用正确的搜索字词...

4 个答案:

答案 0 :(得分:4)

基本上有两种不同的方法。编写自己的函数,迭代返回truefalse的列表,具体取决于是否找到3:

contains_3([3|_]) -> true;
contains_3([_|T]) -> contains_3(T);
contains_3([]) -> false.

第二个是使用已经定义的函数来进行实际迭代,直到对list元素的测试为真并为其提供测试。 lists:any会返回truefalse,具体取决于测试是否对至少一个元素成功:

contains_3(List) -> lists:any(fun (E) -> E =:= 3 end, List).

会做同样的事情。你选择哪一个取决于你。第二个可能更接近设计模式,但我觉得即使你使用它,你应该知道它是如何在内部工作的。在这种情况下,它是微不足道的,非常接近明确的情况。

这是一件很常见的事情,但它是否会被归类为我不知道的设计模式。它似乎是如此基本,在某种意义上“微不足道”,我会毫不犹豫地将其称为设计模式。

答案 1 :(得分:3)

自从我做了任何erlang以来已经有一段时间了,所以我不会尝试为你提供语法,但是erlang和OTP都有等待你的解决方案。

产生一个代表该功能的过程;让它遍历列表,产生尽可能多的进程,让您觉得适当地执行有效的每元素计算。

将每个进程链接到函数进程,并在返回第一个结果后让函数进程终止。

让erlang / otp清理剩余的进程。

答案 2 :(得分:2)

正如已经回答的那样,您的解决方案是使用列表:any / 2。

看到你想要它的并发版本:

any(F, List) ->
   Parent = self(),
   Pid = spawn(fun() -> spawner(Parent, F, List) end),
   receive {Pid, Result} -> Result
   end,
   Result.

spawner(Parent, F, List) ->
   Spawner = self(),
   S = spawn_link(fun() -> wait_for_result(Spawner, Parent, length(List)) end),
   [spawn_link(fun() -> run(S, F) end) || X <- List],
   receive after infinity -> ok end.

wait_for_result(Spawner, Parent, 0) ->
   Parent ! {Spawner, false},
   exit(have_result);
wait_for_result(Spawner, Parent, Children) ->
   receive
     true -> Parent ! {Spawner, true}, exit(have_result);
     false -> wait_for_result(Spawner, Parent, Children -1)
   end.

run(S, F) ->
  case catch(F()) of
    true -> S ! true;
    _ -> S ! false
  end.

请注意,当“wait_for_children”进程执行退出(has_result)时,所有子进程(“运行”进程)将会死亡。

完全未经测试......啊,到底是什么。我会做一个例子:

4> play:any(fun(A) -> A == a end, [b,b,b,b,b,b,b,b]).
false
5> play:any(fun(A) -> A == a end, [b,b,b,b,b,b,a,b]).
true

可能仍然存在错误(可能存在错误)。

答案 3 :(得分:0)

您可能希望查看plists模块:http://code.google.com/p/plists/虽然我不知道plists:any是否处理

  

(a)在收到的第1个{success}上,告诉其他子流程停止处理&amp;尽快退出