代码之家  ›  专栏  ›  技术社区  ›  Sam

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

  •  0
  • Sam  · 技术社区  · 8 年前

    二郎新来了。我有一个列表,比如

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

    我没有使用键或重新导出参数,它们只是由couchdb提供的。我不能在我的函数之外定义/声明任何东西,这是不允许的。

    3 回复  |  直到 8 年前
        1
  •  2
  •   Hynek -Pichi- Vychodil Paulo Suassuna    8 年前

    如果您在Intel(R)Core(TM)i5-7200U CPU@2.50GHz的OTP20中寻找最高效的(12-25ms,1米(1000x1000)解决方案,这取决于您是否达到GC,每个值大约30个CPU周期,对于解释语言huh来说也不错):

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

    编辑 以下内容:

    实际上,没有最有效的解决方案。 总和/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.
    
        2
  •  2
  •   bxdoan    8 年前

    希望有帮助:)

    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.
    
        3
  •  2
  •   Pascal    8 年前

    您的解决方案似乎可以工作,即使您有未使用的参数(键和重新导出),但您仍然需要知道内部列表的大小,这在初始累加器中是隐式的: [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.