Functional programming 在Erlang中的列表中替换

Functional programming 在Erlang中的列表中替换,functional-programming,erlang,Functional Programming,Erlang,我正试图学习一些Erlang,但却很难找到解决特定问题的最佳方法。以下是我正在做的: 我有一个大的二维数据数组(列表列表),其值由独立的进程计算。这些进程在完成计算后向聚合器发回一条消息,其中包含结果。我的问题是如何将聚合数据放入一个新的大数组中。我可以这样做: aggregator(Array) -> receive {Value1_1, {1, 1}} -> Value1_1 = Value1_1 end, rece

我正试图学习一些Erlang,但却很难找到解决特定问题的最佳方法。以下是我正在做的:

我有一个大的二维数据数组(列表列表),其值由独立的进程计算。这些进程在完成计算后向聚合器发回一条消息,其中包含结果。我的问题是如何将聚合数据放入一个新的大数组中。我可以这样做:

aggregator(Array) ->
    receive
        {Value1_1, {1, 1}} ->
            Value1_1 = Value1_1
    end,
    receive
        {Value1_2, {1, 2}} ->
            Value1_2 = Value1_2
    end,
    % ...
    {{Value1_1, Value2_1},
     {Value2_1, Value2_2}}
aggregator(Array) when is_full(Array) -> %% I think I know how to write is_full.
    Array;
aggregator(Array) ->
    receive
        {Value, {X, Y}} ->
            aggregator(replace_2d(Array, X, Y)) %% Is this the way to go?
    end.
aggregator(X, Y) ->
    aggregator(X, Y, []).

aggregator(_, 0, Accum) ->
    Accum;
aggregator(X, Y, Accum) ->
    aggregator(X, Y-1, [aggr_x(X, Y, [])|Accum]).

aggr_x(0, _, AccX) ->
    AccX;
aggr_x(X, Y AccX) ->
    receive
      {Value, {X, Y}} ->
        aggr_x(X-1, Y, [Value|AccX]) ->
    end.
但这是非常跛脚和规模差。我想我要做的是:

aggregator(Array) ->
    receive
        {Value1_1, {1, 1}} ->
            Value1_1 = Value1_1
    end,
    receive
        {Value1_2, {1, 2}} ->
            Value1_2 = Value1_2
    end,
    % ...
    {{Value1_1, Value2_1},
     {Value2_1, Value2_2}}
aggregator(Array) when is_full(Array) -> %% I think I know how to write is_full.
    Array;
aggregator(Array) ->
    receive
        {Value, {X, Y}} ->
            aggregator(replace_2d(Array, X, Y)) %% Is this the way to go?
    end.
aggregator(X, Y) ->
    aggregator(X, Y, []).

aggregator(_, 0, Accum) ->
    Accum;
aggregator(X, Y, Accum) ->
    aggregator(X, Y-1, [aggr_x(X, Y, [])|Accum]).

aggr_x(0, _, AccX) ->
    AccX;
aggr_x(X, Y AccX) ->
    receive
      {Value, {X, Y}} ->
        aggr_x(X-1, Y, [Value|AccX]) ->
    end.

但是我没有看到任何内置的工具来替换基于内置数组索引的值。这让我怀疑,我缺少了一些实现目标的惯用方法,而这些方法对于有函数式编程经验的人来说更为明显。是吗?我的方法全错了吗?我是否应该自己编写一个replace_2d函数并称之为good?

在构建不完整列表时,您是否必须处理它,即元素必须位于正确的位置

如果真的需要,二叉树可能有助于提高基于索引的更新的效率

但是如果不是,只需在值进入时收集它们,然后排序

有一个可能具有您想要的语义的。但它是一个功能性容器,可能没有您想要的性能特征,尤其是在处理大型阵列时

然而,您的第一次尝试可能有一些优点,只要递归地进行即可。(如果您知道列表的大小。)

完全未经测试,但从以下内容开始:

aggregator(Array) ->
    receive
        {Value1_1, {1, 1}} ->
            Value1_1 = Value1_1
    end,
    receive
        {Value1_2, {1, 2}} ->
            Value1_2 = Value1_2
    end,
    % ...
    {{Value1_1, Value2_1},
     {Value2_1, Value2_2}}
aggregator(Array) when is_full(Array) -> %% I think I know how to write is_full.
    Array;
aggregator(Array) ->
    receive
        {Value, {X, Y}} ->
            aggregator(replace_2d(Array, X, Y)) %% Is this the way to go?
    end.
aggregator(X, Y) ->
    aggregator(X, Y, []).

aggregator(_, 0, Accum) ->
    Accum;
aggregator(X, Y, Accum) ->
    aggregator(X, Y-1, [aggr_x(X, Y, [])|Accum]).

aggr_x(0, _, AccX) ->
    AccX;
aggr_x(X, Y AccX) ->
    receive
      {Value, {X, Y}} ->
        aggr_x(X-1, Y, [Value|AccX]) ->
    end.

记住,这将首先接收高索引元素,而对于大型数据集,收件箱可能变得非常满,并且您需要考虑在接收与深度收件箱匹配的性能。

在结尾是对我是错的解释。

数组的实现使得当函数语义允许时,它们可以在O(1)时间内更新。 也就是说,如果只引用一次,并且在计算新数组时立即删除引用,则将通过覆盖更改的条目来计算新数组。由于这一切都是由编译器/解释器处理的,因此您仍然拥有函数式编程的安全性

因为Erlang数组只是一维的,所以您需要自己进行索引计算。。 也许每行有一个聚合器是合理的,并且在多个处理器上运行时会有所帮助

示例代码假定0是行和列的Origo,并且每个位置将只接收一次

aggregator(Rows, Cols)->
  Size = Rows*Cols,
  aggregator(Cols, array:new(Size), Size).

aggregator(Cols, Array, 0)->Array;
aggregator(Cols, Array, N)->
  receive
    {Value, {Col, Row}}->
      aggregator(Cols, array:set(Col+Row*Cols, Value, Array), N-1)
  end.
我已经通过运行以下程序测试了固定阵列结构:

test_array(Size, Times)->
  test_array(Size, array:new(Size, {default, 0}), Times).
test_array(_Size, Array, 0)->
  Array;
test_array(Size, Array, Times) ->
  X = random:uniform(Size)-1,
  V = array:get(X, Array),
  test_array(Size, array:set(X, V+1, Array), Times-1).
时间=100000000,大小为[1010010001000000]。 以秒为单位的挂钟时间为:[101129140182241] 这大致是关于O(log(Size))的,而我原本预计是关于O(1)。
因此,我已经证明我是错的,但也许在未来,阵列的行为将更像我所认为的那样。

我正在研究阵列模块。不过,我不知道如何递归地执行第一种方法。对不起,这是两个不同的建议——使用数组模块或基于模式匹配递归地执行接收。我在这里给出的代码基本上与您的第一个剪贴代码相同,但是有一个递归调用的接收。它返回数组而不是元组的元组。。。。或按排序顺序收集值。您是指array()数据类型,还是指列表?array()数据类型只是一个元组,我不认为编译器知道关于它的任何具体信息。您所指的这种优化通常适用于所有元组吗?你知道有什么解释这一点的阅读材料吗?谢谢,我已经测试了一个固定数组,看来你是对的,我记错了。我将更新我的答案,以反映这一点。您不能将is_已满(数组)作为守卫。只允许使用BIF。在函数内部执行case子句。