在Erlang的列表中替换

时间:2010-10-08 17:14:44

标签: functional-programming erlang

我正在尝试学习一些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.

但是我没有看到任何基于内置插件中的数组索引替换值的内置工具。这让我怀疑我错过了一些实现目标的惯用方法,对于有功能编程经验的人来说更为明显。我呢?我的方法都错了吗?我应该给自己写一个replace_2d函数并称之为好吗?

3 个答案:

答案 0 :(得分:3)

最后解释我的错误。

实现数组,以便在功能语义允许时,它们在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,大小为[10,100,1000,10000,100000]。 挂钟时间以秒为单位:[101,129,140,​​182,241] 这非常粗略地约为O(log(Size)),我希望O(1)。 因此,我已经证明我错了,但也许将来阵列的行为会更像我认为的那样。

答案 1 :(得分:2)

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

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

如果不是,只需收集值,然后排序

答案 2 :(得分:2)

有一个array module可能有您正在寻找的语义。但它是一个功能容器,可能没有您正在寻找的性能特征,尤其是。你正在处理一个大阵列。

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

完全未经测试,但从这样的事情开始:

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.

请注意,这将首先获得高索引元素,而对于大型数据集,您的收件箱可能会非常充实,并且您需要考虑在具有深收件箱的接收上匹配的性能。