我正在尝试学习一些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函数并称之为好吗?
答案 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.
请注意,这将首先获得高索引元素,而对于大型数据集,您的收件箱可能会非常充实,并且您需要考虑在具有深收件箱的接收上匹配的性能。