【问题标题】:Iterate over a cartesian product in Erlang without generating a list first在 Erlang 中迭代笛卡尔积而不首先生成列表
【发布时间】:2014-12-03 23:34:15
【问题描述】:

什么是 Erlang 等价于以下 Python 代码:

for x in range(9):
    for y in range(9):
        for z in range(9):
            foo(x, y, z)

我知道我可以先用C = [{X,Y,Z} || X<- lists:seq(1,9), Y<- lists:seq(1,9), Z<- lists:seq(1,9)] 然后foo([])->done; foo([H|T])->blah blah. 生成产品

如何在没有辅助列表的情况下仅使用递归?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    你可以用三个递归函数来做到这一点。

    您也许可以通过函数头中的一些复杂模式匹配来做到这一点。

    但跳过创建辅助列表的最简单方法是在列表理解中调用您的函数

    C = [foo(X, Y, Z) || X<- lists:seq(1,9), 
                         Y<- lists:seq(1,9),  
                         Z<- lists:seq(1,9)]
    

    foo/3 处理一个元素。

    【讨论】:

      【解决方案2】:

      列表理解仍然迫使您在内存中创建辅助列表。 在处理大量数据集的情况下,您应该避免使用它。每次编写递归函数也很尴尬,所以我想出了自己的通用函数。它的遍历速度比直接递归或列表理解要慢一些,但它的内存稳定、通用且易于使用。

      用法:

      (for({10}))(
          fun (X) -> io:format("~p ",[X]) end).
      > 1 2 3 4 5 6 7 8 9 10
      
      (for({10, -10, -2}))(
          fun (X) -> io:format("~p ",[X]) end).
      > 10 8 6 4 2 0 -2 -4 -6 -8 -10
      

      也适用于列表:

      (for(lists:seq(10, -10, -2)))(
          fun (X) -> io:format("~p ",[X]) end).
      > 10 8 6 4 2 0 -2 -4 -6 -8 -10
      

      也可以将 step 或 guard 定义为函数:

      (for({256, 1.1, fun (X) -> math:sqrt(X) end, fun (X, Range) -> X > Range end}))(
          fun (X) -> io:format("~p ",[X]) end).
      > 256 16.0 4.0 2.0 1.4142135623730951 1.189207115002721
      

      如果你传递一个有两个参数的函数,那么你可以像使用列表一样使用累加器功能:foldl/3。您还需要将初始累加器传递给 for:

      Fact = (for(1, {1, 5}))(
          fun(X, Acc) ->
            X * Acc
          end),
      io:format("~p", [Fact]).
      > 120
      
      e_fact(N) ->
        {_, E} = (for({1, 1}, {1, N}))( % i assumed  1/0! equals 1
          fun(X, {LastFact, Sum}) ->
            Fact = LastFact * X,
            {Fact, Sum + 1 / Fact}
          end),
        E.
      io:format("e=~p", [e_fact(10)]).
      > e=2.7182818011463845
      

      步进和保护功能也可以依赖于累加器。只需多传一个参数即可。

      寻找毕达哥拉斯三元组的嵌套循环。使用闭包很容易:

      pyth_lists(N) ->
        [io:format("~p ", [{A, B, C}]) ||
          A <- lists:seq(1, N),
          B <- lists:seq(A + 1, N),
          C <- lists:seq(B + 1, N),
          A * A + B * B == C * C].
      
      pyth_for(N) ->
        (for({1, N}))(
          fun(A) ->
            (for({A + 1, N}))(
              fun(B) ->
                (for({B + 1, N}))(
                  fun(C) ->
                    case A * A + B * B == C * C of
                      true -> io:format("~p ", [{A, B, C}]);
                      false -> ok
                    end
                  end)
              end)
          end).
      

      对于外部存储库来说太小了。我将它保存在我的实用程序模块中。 如果你觉得有帮助,这里是代码:

      -export([for/1, for/2]).
      
      for(Through) ->
        for([], Through).
      
      for(InitAcc, Opts) when is_tuple(Opts) ->
        {Init, Range, Step, Guard} = for_apply_default_opts(Opts),
        fun(Fun) -> 
          UpdFun = if
            is_function(Fun, 1) ->
              fun(I, _FAcc) -> Fun(I) end;
            is_function(Fun, 2) ->
              Fun
          end,
          for_iter(UpdFun, InitAcc, Init, Range, Step, Guard) end;
      
      for(InitAcc, List) when is_list(List) ->
        fun(Fun) -> for_list_eval(Fun, InitAcc, List) end.
      
      for_iter(Fun, Acc, I, Range, Step, Guard) ->
        case Guard(I, Range, Acc) of
          false ->
            Acc;
          true ->
            NewAcc = Fun(I, Acc),
            for_iter(Fun, NewAcc, Step(I, NewAcc), Range, Step, Guard)
        end.
      
      for_list_eval(Fun, Acc, List) ->
        if
          is_function(Fun, 1) ->
            lists:foreach(Fun, List);
          is_function(Fun, 2) ->
            lists:foldl(Fun, Acc, List)
        end.
      
      for_apply_default_opts({Range}) ->
        DefaultInit = 1,
        for_apply_default_opts({DefaultInit, Range});
      
      for_apply_default_opts({Init, Range}) ->
        DefaultStep = 1,
        for_apply_default_opts({Init, Range, DefaultStep});
      
      for_apply_default_opts({Init, Range, Step}) ->
        DefaultGuard = case (Step > 0) or is_function(Step) of
                         true -> fun(I, IterRange, _Acc) -> I =< IterRange end;
                         false -> fun(I, IterRange, _Acc) -> I >= IterRange end
                       end,
        for_apply_default_opts({Init, Range, Step, DefaultGuard});
      
      for_apply_default_opts({Init, Range, Step, Guard}) when is_function(Guard, 2) ->
        for_apply_default_opts({Init, Range, Step, fun(I, IterRange, _Acc) -> Guard(I, IterRange) end});
      
      for_apply_default_opts({Init, Range, Step, DefaultGuard}) when is_number(Step) ->
        for_apply_default_opts({Init, Range, fun(I, _Acc) -> I + Step end, DefaultGuard});
      
      for_apply_default_opts({Init, Range, Step, DefaultGuard}) when is_function(Step, 1) ->
        for_apply_default_opts({Init, Range, fun(I, _Acc) -> Step(I) end, DefaultGuard});
      
      for_apply_default_opts({_Init, _Range, _Step, _DefaultGuard} = Opts) ->
        Opts.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-27
        • 2016-10-08
        • 2017-09-28
        • 2016-05-07
        • 1970-01-01
        • 2022-11-17
        • 2021-05-06
        • 1970-01-01
        相关资源
        最近更新 更多