代码之家  ›  专栏  ›  技术社区  ›  monch1962

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

  •  5
  • monch1962  · 技术社区  · 15 年前

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

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

    举一个简单的例子,假设L是一个整数列表,如果L中的元素是3,F返回{success},对于任何其他值返回{fail}。我想尽快找到L中是否有3;我不在乎有多少个3,只在乎是否至少有一个3存在。f可以如下所示:

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

    如何遍历int列表以确定该列表是否包含至少一个3,并尽快返回?

    当然,这是一个常见的功能设计模式,我只是没有在谷歌使用正确的搜索词。。。

    4 回复  |  直到 15 年前
        1
  •  2
  •   Daniel Luna    15 年前

    正如已经得到的回答,你的解决办法是使用lists: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 \u for \u children”进程退出(have \u result)时,所有子进程(“run”进程)都将死亡。

    完全未经测试。。。啊,见鬼。我举个例子:

    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
    

    可能仍然有bug(可能也有)。

        2
  •  4
  •   rvirding    15 年前

    基本上有两种不同的方法。或者编写自己的函数,遍历返回的列表 true false 取决于它是否找到3:

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

    第二种方法是使用一个已经定义的函数来执行实际的迭代,直到列表元素上的测试为真,并为其提供测试。 lists:any 是的 取决于至少一个元素的测试是否成功:

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

    会做同样的事。你选哪一个取决于你自己。第二种可能更接近于设计模式,但我觉得即使你使用它,你也应该对它的内部工作方式有一个想法。在这种情况下,它是微不足道的,非常接近显式的情况。

    这是一件非常常见的事情,但我不知道它是否会被归类为一种设计模式。它看起来如此基本,从某种意义上说是“琐碎的”,以至于我不敢称之为设计模式。

        3
  •  3
  •   Recurse    15 年前

    我已经有一段时间没有做任何erlang了,所以我不会尝试向您提供语法,但是erlang和OTP有解决方案等着您。

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

    让erlang/otp来清理其余的进程。

        4
  •  0
  •   Alexey Romanov    15 年前

    plists 模块: http://code.google.com/p/plists/ plists:any 手柄

    (a) 在收到第一个{success}时,告诉其他子进程停止处理&尽快离开