找到任何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个数字,那么构造的列表理解甚至需要更长的时间。如果我要使用列表理解来解决这个问题,我做得对吗?如果是的话,为什么需要太长时间?请提供一个可能更快的解决方案,也许使用循环。
答案 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倍(或更多,因为产生的垃圾更少)。同时减少B
,C
和D
列表的大小也会有所改善。
但是那里有一些代码重复。不幸的是,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]