Суммируйте список списков целых чисел на индекс в эрланге - PullRequest
0 голосов
/ 12 июня 2018

эрланг новичок здесь.У меня есть список списков, таких как

[[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 голосов
/ 12 июня 2018

Ваше решение работает, даже если у вас есть неиспользуемые параметры (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.
0 голосов
/ 13 июня 2018

Если вы ищете наиболее эффективный (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.
0 голосов
/ 12 июня 2018

Надеюсь, что поможет:)

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...