2014-11-24 44 views
2

什麼是二郎神等同於以下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.

如何先做生成產品我沒有一個輔助列表,只使用遞歸?

回答

1

你可以用三個遞歸函數來做到這一點。

您可能可以通過函數頭中的某些複雜模式匹配來完成此操作。跳過輔助列表的創建

但最簡單的方法就是

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

foo/3過程中的一個元素通話清單裏面理解你的函數。

0

列表理解仍然強制您在內存中創建輔助列表。 如果處理大量的數據集,你應該避免它。每次寫遞歸函數也很尷尬,所以我想出了自己的泛型函數。遍歷的速度比直接遞歸或列表理解慢一點,但內存穩定,通用且易於使用。

用法:

(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 

它也可以定義步或保護的功能:如果你傳遞給了

(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。您還需要將初始累加器傳遞給:

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.