array基础
Eshell V5.9 (abort with ^G) 1> A1 = array:set(17, true, array:new()). {array,18,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 2> array:set(17, undefined, array:new()). %%即使赋值的时候使用的是默认值,对应数据组依然会展开 {array,18,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 3> array:set(1214, true, A1). {array,1215,10000,undefined, {{{10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}, 100,100,100,100,100,100,100,100,100,100}, {100,100, {10, {undefined,undefined,undefined,undefined,true,undefined, undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}, 100,100,100,100,100,100,100,100}, 1000,1000,1000,1000,1000,1000,1000,1000,1000}} %% array:reset 2> array:set(12,test,array:new()). {array,13,100,undefined, {10, {undefined,undefined,test,undefined,undefined,undefined, undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 4> array:reset(12,v(2)). {array,13,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 5> 看一下扩展的例子: 12> array:new({default,null}). {array,0,10,null,10} 13> array:get(24, v(12)). null 15> array:default( v(12)). null 16> array:set(124, true, A1). {array,125,1000,undefined, {{10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}, {10,10, {undefined,undefined,undefined,undefined,true,undefined, undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10}, 100,100,100,100,100,100,100,100,100}} 17> array:set(1214, true, A1). {array,1215,10000,undefined, {{{10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}, 100,100,100,100,100,100,100,100,100,100}, {100,100, {10, {undefined,undefined,undefined,undefined,true,undefined, undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}, 100,100,100,100,100,100,100,100}, 1000,1000,1000,1000,1000,1000,1000,1000,1000}} 18>
还是tuple
-record(array, {size :: non_neg_integer(), %% number of defined entries max :: non_neg_integer(), %% maximum number of entries %% in current tree default, %% the default value (usually 'undefined') elements %% the tuple tree }).
Eshell V5.9 (abort with ^G) 1> erlang:make_tuple(5,a). {a,a,a,a,a} 2> erlang:make_tuple(4, []). {[],[],[],[]} 3> erlang:make_tuple(9, [],[{1,a},{3,q}]). {a,[],q,[],[],[],[],[],[]} 4> Eshell V5.9 (abort with ^G) 1> T={a,b,c,d}. {a,b,c,d} 2> setelement(1,T,hello). {hello,b,c,d} 3> setelement(2,T,kk). {a,kk,c,d}
-define(NEW_NODE(S), % beware of argument duplication! setelement((?NODESIZE+1),erlang:make_tuple((?NODESIZE+1),(S)),(S))). -define(NEW_LEAF(D), erlang:make_tuple(?LEAFSIZE,(D))). is_array(#array{size = Size, max = Max}) when is_integer(Size), is_integer(Max) -> true; is_array(_) -> false. size(#array{size = N}) -> N; size(_) -> erlang:error(badarg). default(#array{default = D}) -> D; default(_) -> erlang:error(badarg). is_fix(#array{max = 0}) -> true; is_fix(#array{}) -> false. fix(#array{}=A) -> A#array{max = 0}. relax(#array{size = N}=A) -> A#array{max = find_max(N-1, ?LEAFSIZE)}. %%LEAFSIZE = 10 find_max(I, M) when I >= M -> find_max(I, ?extend(M)); find_max(_I, M) -> M.
set(I, Value, #array{size = N, max = M, default = D, elements = E}=A) when is_integer(I), I >= 0 -> if I < N -> %%%小于当前Size A#array{elements = set_1(I, E, Value, D)}; I < M -> %%%超过当前的Size但是小于MAX 点 %% (note that this cannot happen if M == 0, since N >= 0) A#array{size = I+1,elements = set_1(I, E, Value, D)}; M > 0 -> %%%没有Fix大小 会进行扩容 {E1, M1} = grow(I, E, M), A#array{size = I+1, max = M1,elements = set_1(I, E1, Value, D)}; true -> erlang:error(badarg) end; set(_I, _V, _A) -> erlang:error(badarg). %% See get_1/3 for details about switching and the NODEPATTERN macro. set_1(I, E=?NODEPATTERN(S), X, D) -> I1 = I div S + 1, setelement(I1, E, set_1(I rem S, element(I1, E), X, D)); set_1(I, E, X, D) when is_integer(E) -> expand(I, E, X, D); set_1(I, E, X, _D) -> setelement(I+1, E, X). %% Enlarging the array upwards to accommodate an index `I' grow(I, E, _M) when is_integer(E) -> M1 = find_max(I, E), {M1, M1}; grow(I, E, M) -> grow_1(I, E, M). grow_1(I, E, M) when I >= M -> grow(I, setelement(1, ?NEW_NODE(M), E), ?extend(M)); grow_1(_I, E, M) -> {E, M}. %% Insert an element in an unexpanded node, expanding it as necessary. expand(I, S, X, D) when S > ?LEAFSIZE -> S1 = ?reduce(S), setelement(I div S1 + 1, ?NEW_NODE(S1), expand(I rem S1, S1, X, D)); expand(I, _S, X, D) -> setelement(I+1, ?NEW_LEAF(D), X).
Eshell V5.9 (abort with ^G) 1> A1 = array:set(17, true, array:new()). {array,18,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}}
%% -define(NODEPATTERN(S), {_,_,_,_,_,_,_,_,_,_,S}). % NODESIZE+1 elements! get(I, #array{size = N, max = M, elements = E, default = D}) when is_integer(I), I >= 0 -> if I < N -> get_1(I, E, D); M > 0 -> D; true -> erlang:error(badarg) end; get(_I, _A) -> erlang:error(badarg). %% The use of NODEPATTERN(S) to select the right clause is just a hack, %% but it is the only way to get the maximum speed out of this loop %% (using the Beam compiler in OTP 11). get_1(I, E=?NODEPATTERN(S), D) -> get_1(I rem S, element(I div S + 1, E), D); get_1(_I, E, D) when is_integer(E) -> D; get_1(I, E, _D) -> element(I+1, E).
20> A = array:from_list([1,2,3,4,5,a,b,c,d,e,f,g]). {array,12,100,undefined, {{1,2,3,4,5,a,b,c,d,e}, {f,g,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 23> {_,_,_,_,E} =A. {array,12,100,undefined, {{1,2,3,4,5,a,b,c,d,e}, {f,g,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 24> {_,_,_,_,_,_,_,_,_,_,S} = E . {{1,2,3,4,5,a,b,c,d,e}, {f,g,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10} 25> S. 10
1> A= array:set(17, true, array:new()). {array,18,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 2> A2= array:set(30, ki, A). {array,31,100,undefined, {10, {undefined,undefined,undefined,undefined,undefined, undefined,undefined,true,undefined,undefined}, 10, {ki,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined,undefined}, 10,10,10,10,10,10,10}} 3> array:sparse_to_list(A2). [true,ki] 4>
数据结构转换
Eshell V5.9 (abort with ^G) 1> 1> array:from_list(lists:seq(1,12)). {array,12,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 2> array:to_list(v(1)). [1,2,3,4,5,6,7,8,9,10,11,12] 3> array:sparse_to_list(v(1)). [1,2,3,4,5,6,7,8,9,10,11,12] 4> array:set(17,kk,v(1)). {array,18,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined,kk, undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 5> array:to_list(v(4)). [1,2,3,4,5,6,7,8,9,10,11,12,undefined,undefined,undefined, undefined,undefined,kk] 6> array:sparse_to_list(v(4)). [1,2,3,4,5,6,7,8,9,10,11,12,kk] 7> array:from_list(v(6)). {array,13,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,kk,undefined,undefined,undefined,undefined,undefined, undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 8> array:from_list(v(5)). {array,18,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined,kk, undefined,undefined}, 10,10,10,10,10,10,10,10,10}}
Eshell V5.9 (abort with ^G) 1> array:from_list(lists:seq(1,12)). {array,12,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 2> array:set(17,kk,v(1)). {array,18,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined,kk, undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 3> array:to_orddict(v(1)). [{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,10},{10,11},{11,12}] 4> array:to_orddict(v(2)). [{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,10},{10,11},{11,12},{12,undefined},{13,undefined},{14,undefined},{15,undefined},{16,undefined},{17,kk}] 5> array:sparse_to_orddict(v(2)). [{0,1},{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,10},{10,11},{11,12},{17,kk}] 6> array:from_orddict(v(4)). {array,18,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined,kk, undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 7> array:from_orddict(v(5)). {array,18,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined,kk, undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 8> array:from_orddict(v(3)). {array,12,100,undefined, {{1,2,3,4,5,6,7,8,9,10}, {11,12,undefined,undefined,undefined,undefined,undefined, undefined,undefined,undefined}, 10,10,10,10,10,10,10,10,10}} 9>
Code snippet
Eshell V5.9 (abort with ^G) 1> F=fun(M,N)->{M,N} end. #Fun<erl_eval.12.111823515> 2> F2=fun(K)->F(K,if K>0->K;true -> 100 end) end. #Fun<erl_eval.6.111823515> 3> F2(10). {10,10} 4> F2(-1). {-1,100} 5> 5> F=fun(E={_,_,A})-> {A} end . #Fun<erl_eval.6.111823515> 7> F({1,2,a}). {a} 8> F2=fun({_,_,A}=E)-> {A} end . #Fun<erl_eval.6.111823515> 9> F2({1,2,a}). {a}
Ya解决方案
2012-07-11 15:40 更新
https://github.com/baryluk/ral
% Random access list. % Random access lists (ral) is a functional (immutable) data % structure which are better (in speed) both from normal lists, % and from balanced binary search trees. % Time complexity of various basic operations % % Operation RAL List BST % head O(1) O(1) O(log n) % tail O(1) O(1) O(log n) % cons O(1) O(1) O(log n) % nth O(log n) O(n) O(log n) % nthtail O(log n) O(n) O(log n) % % in some situations nth or nthtail can be faster in RAL. O(log n) is worst case complexity. % for some values it is faster.
LYSE上一段很好的总结:
Erlang arrays, at the opposite of their imperative counterparts, are not able to have such things as constant-time insertion or lookup. Because they're usually slower than those in languages which support destructive assignment and that the style of programming done with Erlang doesn't necessary lend itself too well to arrays and matrices, they are rarely used in practice.
Generally, Erlang programmers who need to do matrix manipulations and other uses requiring arrays tend to use concepts called Ports to let other languages do the heavy lifting, or C-Nodes, Linked in drivers and NIFs (Experimental, R13B03+).
Arrays are also weird in the sense that they're one of the few data structures to be 0-indexed (at the opposite of tuples or lists), along with indexing in the regular expressions module. Be careful with them.
Link: http://learnyousomeerlang.com/a-short-visit-to-common-data-structures#arrays
晚安!