为什么这个List理解在Erlang / OTP 20上评估需要太长时间?

时间:2017-11-28 15:00:14

标签: erlang

找到任何5个数字,其总和= 100.这可以在一个循环中完成,但我向朋友说明列表理解只是意识到这需要超过30分钟在我的Mac Book Pro,核心i7,2.2GHz < / p>

[[A,B,C,D,E] || A <- lists:seq(1,100),B <- lists:seq(1,100),C <- lists:seq(1,100),D <- lists:seq(1,100),E <- lists:seq(1,100),(A + B + C + D + E) == 100]

如果问题被改为连续5个数字,那么构造的列表理解甚至需要更长的时间。如果我要使用列表理解来解决这个问题,我做得对吗?如果是的话,为什么需要太长时间?请提供一个可能更快的解决方案,也许使用循环。

4 个答案:

答案 0 :(得分:4)

多个生成器的行为类似于列表上的嵌套循环,每次调用列表:seq()每次都会被完全评估。这需要很长时间,并且花费大部分时间来分配列表单元格并再次收集垃圾。但是因为无论如何它们都评估到相同的常量列表,你可以将它重写为L =列表:seq(1,100),[[A,B,C,D,E] || A&lt; -L,B&lt; -L,C&lt; -L,D&lt; -L,E&lt; -L,(A + B + C + D + E)== 100]。此外,在shell中运行它将比编译模块慢很多。在我的macbook上,编译的代码在大约2分30秒内完成。这只是使用单核心。使用[native]进行编译使其在60秒内运行平稳。

答案 1 :(得分:3)

因为它在创建过滤器之前“创建”了5个元素列表的100 ^ 5列表的所有元素,它代表50000000000个元素。

答案 2 :(得分:2)

当我们在编程中使用并发时,Erlang很强,所以你也可以产生100个进程来处理[1,...,100]的列表。您的笔记本电脑可以轻松计算。例如:

do()->    
    L100 = lists:seq(1,100),
    [spawn(?MODULE, func, [self(), [A], L100, L100, L100, L100]) || 
        A <- L100],    
    loop(100, []).
loop(0, Acc) -> Acc;
loop(N, Acc) ->
    receive
        {ok, Result} ->
            loop(N - 1, Acc ++ Result)
    end.

func(Pid, LA, LB, LC, LD, LE) ->
    Result = [[A,B,C,D,E] ||
             A <- LA,B <- LB,C <- LC,D <- LD,E <- LE,(A + B + C + D + E) == 100],
    Pid ! {ok, Result}.

通过上述解决方案,我的i3 2.1GHz笔记本电脑可在1分钟内轻松计算。您还可以生成更多进程以进行更短的计算。 Erlang中的过程是轻量级过程,因此可以轻松启动然后轻松停止。

答案 3 :(得分:1)

一个选项是

[[A,B,C,D,100-A-B-C-D] || A <- lists:seq(1,100), B <- lists:seq(1,100-A), C <- lists:seq(1,100-A-B), D <- lists:seq(1,100-A-B-C), 100-A-B-C-D > 0]

当最多只有一个成功时,所有可能的E都不会被列举为快100倍(或更多,因为产生的垃圾更少)。同时减少BCD列表的大小也会有所改善。

但是那里有一些代码重复。不幸的是,Erlang不允许&#34;本地&#34;列表推导中的变量,但您可以使用单元素生成器模拟它们:

[[A,B,C,D,E] || A <- lists:seq(1,100), 
    BMax <- [100-A], B <- lists:seq(1,BMax), 
    CMax <- [BMax-B], C <- lists:seq(1,CMax), 
    DMax <- [CMax-C], D <- lists:seq(1,DMax), 
    E <- [100-A-B-C-D], E > 0]

或者避免重复lists:seq次调用,正如@RichardC指出的那样:

L = lists:seq(1, 100),
[[A,B,C,D,E] || A <- L, 
    BMax <- [100-A], B <- L, B =< BMax,
    CMax <- [BMax-B], C <- L, C =< CMax,
    DMax <- [CMax-C], D <- L, D =< DMax, 
    E <- [100-A-B-C-D], E > 0]