在erlang中汇总每个索引的整数列表

时间:2018-06-12 01:54:11

标签: erlang

erlang新手在这里。我有一个列表,如

[[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]

我没有使用Keys或ReReduce参数,它们只是由CouchDB提供。我不能在我的函数之外定义/声明任何东西,不允许这样做。

3 个答案:

答案 0 :(得分:2)

希望有所帮助:)

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]).

shell中的结果:

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

因此,您的func会在下方:

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

答案 1 :(得分:2)

即使您有未使用的参数(Keys和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.

答案 2 :(得分:2)

如果您在英特尔(R)Core(TM)i5-7200U CPU @ 2.50GHz上寻找效率最高(12-25ms for 1M(1000x1000)in OTP20,具体取决于您是否点击GC,那么大约每30个CPU周期价值,对于解释性语言也不错嗯)解决方案:

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. 解决方案的有趣版本

Values

鉴于CouchDB reduce函数的限制和属性(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. 永远不会为空)我会认为你的解决方案稍微调整一下就是最优雅的

sum/1

修改

实际上,没有一种最有效的解决方案。上面的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. 对于具有长子列表的列表最有效,例如1000个子列表,其中1000个值如上所述。对于更短的子列表,原始方法似乎更合适。不同之处在于您由于中间数据结构而执行的GC数量。如果你有短的子列表,这个解决方案会更有效率

std::vector