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提供。我不能在我的函数之外定义/声明任何东西,不允许这样做。
答案 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