[Erlang 0069] Erlang ordsets


    ordsets 是lists實現的有序集合.由於數據元素的變動都會觸發重新排序,所以ordsets效率不高,只適用於數據量比較小的場景.ordsets中包含了常見的集合操作:求交集,並集,是否為子集,是否存在交集
 
6> ordsets:intersection([1,2,3,4],[3,4,5,6]).
[3,4]
7> ordsets:union([1,2,3,4],[3,4,5,6]).
[1,2,3,4,5,6]
8> ordsets:is_disjoint([1,2,3,4],[3,4,5,6]).
false
9> ordsets:is_disjoint([1,2,3,4],[31,41,5,6]).
true
10> ordsets:is_subset([1,2,3,4],[31,41,5,6]).
false
11> ordsets:is_subset([1,2,3,4],[1,3]).
false
12> ordsets:is_subset([1,2,3,4],[1,2,3,4,5,31]).
true

  

  這些方法的實現大同小異,都會遍歷兩個集合(實際上就是處理兩個lists):

union([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
    [E1|union(Es1, Set2)];
union([E1|_]=Set1, [E2|Es2]) when E1 > E2 ->
    [E2|union(Es2, Set1)];               % switch arguments!
union([E1|Es1], [_E2|Es2]) ->               %E1 == E2
    [E1|union(Es1, Es2)];
union([], Es2) -> Es2;
union(Es1, []) -> Es1.
 
  看一下ordsets數據元素時的處理邏輯:
add_element(E, [H|Es]) when E > H -> [H|add_element(E, Es)];
add_element(E, [H|_]=Set) when E < H -> [E|Set];
add_element(_E, [_H|_]=Set) -> Set;          %E == H
add_element(E, []) -> [E].
 
del_element(E, [H|Es]) when E > H -> [H|del_element(E, Es)];
del_element(E, [H|_]=Set) when E < H -> Set;
del_element(_E, [_H|Es]) -> Es;               %E == H
del_element(_, []) -> [].
 
  其它的方法實現多是簡單封裝了lists的方法而已比如:from_list實際上就是執行list:usort,is_set判斷是List且已經排序;
 
is_subset([E1|_], [E2|_]) when E1 < E2 ->     %E1 not in Set2
    false;
is_subset([E1|_]=Set1, [E2|Es2]) when E1 > E2 ->
    is_subset(Set1, Es2);
is_subset([_E1|Es1], [_E2|Es2]) ->          %E1 == E2
    is_subset(Es1, Es2);
is_subset([], _) -> true;
is_subset(_, []) -> false.

%% 下面兩個方法僅僅是對lists方法的簡單封裝 
fold(F, Acc, Set) ->
    lists:foldl(F, Acc, Set).
 
filter(F, Set) ->
    lists:filter(F, Set).

 lists:usort的處理過程包含了數據排重:

1> lists:usort([2,1,3,4,2,3,8,9,a,v,c]).
[1,2,3,4,8,9,a,c,v]
2> lists:usort([2,1,3,4,2,3,8,9,[a,c,q,m,x],a,v,c]).
[1,2,3,4,8,9,a,c,v,[a,c,q,m,x]]
3> lists:usort([2,1,3,4,2,3,8,9,[0,c,q,m,x],a,v,c]).
[1,2,3,4,8,9,a,c,v,[0,c,q,m,x]]
4> lists:usort([2,1,3,{zen},4,2,3,8,9,[0,c,q,m,x],a,v,c]).
[1,2,3,4,8,9,a,c,v,{zen},[0,c,q,m,x]]

 

性能相關

   OTP文檔中有一點和ordsets相關的內容 lists:substract(A,B),該操作的復雜度和leng(A)*length(B)成正比,當參與運算的兩個都是長列表的時候就會非常慢了;使用ordsets會好很多:
 
> lists:subtract("123212", "212").   %%   lists:subtract(A, B) is equivalent to A -- B.
"312".

不要這樣做:

        HugeList1 -- HugeList2

替代方案:  
       HugeSet1 = ordsets:from_list(HugeList1),
        HugeSet2 = ordsets:from_list(HugeList2),
        ordsets:subtract(HugeSet1, HugeSet2)        
 
  顯然lists中的元素原始順序非常重要上面的方法就不適用了,要保持數據原始順序,可以這樣做:
        Set = gb_sets:from_list(HugeList2),
        [E || E <- HugeList1, not gb_sets:is_element(E, Set)]
 
 
兩個細節:
1.如果lists中包含重復的元素時,兩種運算不是等價的,HugeList2會移除所有在HugeList1中出現的元素
2.下面的方法比較lists中的元素使用的是相等== 而'--'操作使用的是匹配操作符'=:=';如果這個地方要求苛刻的話,可以使用sets替換為gb_sets,但要注意sets:from_list/1要比gb_sets:from_list/1慢得多.

注意:'--'操作符在處理單個元素時並無大礙:
HugeList1 -- [Element]  %%OK         
 

其它Set模塊

  sets 提供了和ordsets一樣的接口;它的實現和 dict類似,只是存儲的數據元素從鍵值對變成了值, 支持的數據量比ordsets更大一些;和 dict一樣特別適用於 讀密集的場景,比如判斷一個元素是否在集合中.
  gb_sets接口包含了ordsets和 gb_trees所提供的接口, gb_sets和 gb_trees實現類似,只是存儲的數據元素從鍵值對變成了值;gb_sets與sets相比除了讀操作性能差一些,其它操作都更快!gb_sets實現了sets和ordsets相同的接口,並新增了一些方法.
  實際應用中你會看到絕大多數時候都是在使用gb_sets,需要"=:="比較的時候使用sets.
 
官方文檔:
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM