Если вы ищете наиболее эффективный (12-25 мс для 1 М (1000x1000) в OTP20 на процессоре Intel® Core ™ TM i5-7200U с частотой 2,50 ГГц, в зависимости от того, ударите вы по ГХ или нет, около 30 циклов ЦП назначение, неплохое для интерпретируемого языка, да) решение:
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.
Учитывая ограничения и свойства (Values
никогда не будетнапример, пустой) функции сокращения CouchDB Я бы рассмотрел ваше решение с небольшим изменением как наиболее элегантный
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.
Edit :
На самом деле, нетодно наиболее эффективное решение.sum/1
выше будет наиболее эффективным для списков с длинными подсписками, такими как 1000 подсписков с 1000 значениями, как измерено выше.Для гораздо более коротких списков оригинальный подход кажется гораздо более подходящим.Разница в том, сколько 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.