对 erlang 中每个索引的整数列表求和



erlang newbie here.我有一个列表列表,例如

[[0,1,1],[1,0,1],[5,2,9]]

我想对列表中的每个索引求和,以便结果为

[6,3,11]

这就是我到目前为止所拥有的,其中值是我的列表列表:

fun(Keys, Values, ReReduce) ->
lists:foldl(fun(V, A) ->
lists:zipwith(fun(X, Y) -> X+Y end, V, A)
end, [0, 0, 0], Values)
end.

有没有更快/更好的方法来实现这一目标?

其他一些观点—— "值"是列表列表。列表中的每个列表将始终具有 3 个整数。列表中存在未知列表。

例如:[[0,1,1],[2,4,6],[3,3,7],[1,0,1]

我没有使用键或Reduce参数,它们只是被CouchDB期望在那里。我不能在我的函数之外定义/声明任何东西,这是不允许的。

如果您在英特尔(R( 酷睿(TM( i5-7200U CPU @ 2.50GHz 上的 OTP20 中寻找最有效的(12-25ms for 1M (1000x1000( 取决于您是否点击 GC,所以每个值大约 30 个 CPU 周期,对于解释语言来说还不错,呵呵(解决方案:

sum(L) ->
case sum(L, [], 0) of
{_, []} -> [];
{S, Ts} -> [S | sum(Ts)]
end.
sum([], Ts, Acc) -> {Acc, Ts};
sum([[H|T] | L], Ts, Acc) ->
sum(L, [T|Ts], H+Acc);
sum([_|L], Ts, Acc) ->
sum(L, Ts, Acc).

还有更优雅的解决方案:

sum2([]) -> [];
sum2(L) ->
S = lists:sum([H || [H|_] <- L]),
case [T || [_|T] <- L] of
[] -> [];
Ts -> [S | sum2(Ts)]
end.

还有更优雅但不太宽容的解决方案(当上面对输入非常满意时[[], [1,2], [3]]这个会引发错误异常(

sum3([]) -> [];
sum3([[]|_]) -> [];
sum3(L) ->
S = lists:sum([hd(X) || X <- L]),
Ts = [tl(X) || X <- L],
[S | sum3(Ts)].

有趣的sum/1解决方案

fun(Keys, Values, ReReduce) ->
SumAndTail = fun
F([], Ts, Acc) -> {Acc, Ts};
F([[H|T] | L], Ts, Acc) ->
F(L, [T|Ts], H+Acc);
F([_|L], Ts, Acc) ->
F(L, Ts, Acc)
end,
Sum = fun G(L) ->
case SumAndTail(L, [], 0) of
{_, []} -> [];
{S, Ts} -> [S | G(Ts)]
end
end,
Sum(Values)
end.

考虑到CouchDB reduce函数的限制和属性(例如Values永远不会为空(,我会认为您的解决方案经过一些调整是最优雅的

fun(Keys, Values, ReReduce) ->
lists:foldl(fun(V, A) ->
lists:zipwith(fun(X, Y) -> X+Y end, V, A)
end, hd(Values), tl(Values))
end.

编辑

实际上,没有一个最有效的解决方案。 对于具有长子列表的列表,例如上面测量的 1000 个子列表,例如具有 1000 个值的 1000 个子列表,上述sum/1将是最有效的。对于更短的子列表,原始方法似乎更合适。区别在于由于中间数据结构,您执行了多少GC。如果您有简短的子列表,则此解决方案将更加高效

sum5([]) -> [];
sum5([H|T]) ->
sum5(H, T).
sum5(Acc, []) -> Acc;
sum5(Acc, [H|T]) ->
sum5(sum5zip(Acc, H), T).
sum5zip([H1|T1], [H2|T2]) ->
[H1+H2|sum5zip(T1, T2)];
sum5zip([], L2) -> L2;
sum5zip(L1, []) -> L1.

希望对:)有所帮助

d()->
[A,B,C] = [[0,1,1],[1,0,1],[5,2,9]],
F = fun(X,Y,Z) -> X+Y+Z end,
lists:zipwith3(F,A,B,C).

我稍微改变了我的代码,我认为它适应了你

d(L) when hd(L) == [] -> [];
d(L)-> [lists:sum([hd(A) || A <- L ])] ++ d([tl(B) || B <- L]).

外壳结果:

1> test:d([[0,1,1],[1,0,1],[5,2,9]]).
[6,3,11]

所以你的func会喜欢下面:

fun(Keys, Values, ReReduce) ->
d(Values)
end.

你的解决方案似乎有效,即使你有未使用的参数(键和ReReduce(,但你仍然必须知道内部列表的大小,它是隐式的在初始累加器中:[0,0,0]

您可以通过非常小的修改来避免这种情况:

1>F = F = fun(Lists = [_L|_]) when is_list(_L) ->
1>    lists:foldl(
1>        fun(List,AccList) -> lists:zipwith(fun(X,Y) -> X+Y end,List,AccList) end,
1>        hd(Lists),
1>        tl(Lists))
1>    end.
#Fun<erl_eval.6.99386804>
2> F([[1],[2]]).                                                                    
[3]
3> F([[]]).                                                                         
[]
4> F([[0,1,1,2],[1,0,1,5],[5,2,9,4],[8,2,7,1]]).                                                 
[14,5,18,12]
5> F([1,2]).                                                                        
** exception error: no function clause matching erl_eval:'-inside-an-interpreted-fun-'([1,2]) 

@bxdoam提供的第二个功能的工作原理相同,(对我来说(说哪一个性能最好并不明显。

我认为可以通过更换线路来改进 bxdoam 解决方案

d(L)-> [lists:sum([hd(A) || A <- L ])] ++ d([tl(B) || B <- L]).

d(L)-> [lists:sum([d([tl(B) || B <- L]|[hd(A) || A <- L ])]]).

[编辑]

如果内部列表的固定大小为 3,则最简单、最快的解决方案是:

fun(Keys, Values, ReReduce) ->
lists:foldl(fun([X,Y,Z],[Sx,Sy,Sz]) -> [X+Sx,Y+Sy,Z+Sz] end, [0,0,0],Values)
end.

最新更新