Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Erlang:如何更快地从列表中获取唯一对?_Performance_Erlang - Fatal编程技术网

Performance Erlang:如何更快地从列表中获取唯一对?

Performance Erlang:如何更快地从列表中获取唯一对?,performance,erlang,Performance,Erlang,我有一个成对的列表[[1,2],[2,1],[1,3]…]。如何以最快的方式获得唯一对?我写了一个函数,但是太慢了 -module(test). -export([unique/1, unique/2, pairs/1]). unique(L) -> unique(L, []). unique([], UL) -> UL; % L: list of lists unique(L, UL) -> [X,Y] = hd(L), case lists:member(

我有一个成对的列表
[[1,2],[2,1],[1,3]…]
。如何以最快的方式获得唯一对?我写了一个函数,但是太慢了

-module(test).
-export([unique/1, unique/2, pairs/1]).

unique(L) -> unique(L, []).
unique([], UL) -> UL;
% L: list of lists
unique(L, UL) ->
    [X,Y] = hd(L),
    case lists:member([Y,X], L) of
        true ->
            unique(L--[[Y,X]], [[X,Y]|UL]);
        false ->
            unique(tl(L), UL)
    end.

pairs(L) -> [[X,Y] || X <- L, Y <- L, X=/=Y].
我有一个列表长度为9900的配对列表,其中一半是重复的。我正在使用配对列表进行进一步计算。对于原始列表(具有重复对),时间是
3.718s
,如果我过滤掉唯一列表并使用if进行计算,时间是
7.375s
,这更糟糕

我将函数更改为不使用
--
运算符

unique(L, UL) ->
    [X,Y] = hd(L),
    case lists:member([Y,X], L) of
        true ->
            unique(tl(L), [[Y,X]|UL]);
        false ->
            unique(tl(L), UL)
    end.
即使如此,它在
7.375s
时只提高了
0.047s
,这表明该算法不够快

你能指出更好的算法吗?是否有用于此的内置库函数?

谢谢。

您是否尝试过
lists:usort([lists:sort(X)| | xf=fun(X,L)->[X,Y]| | yl=lists:seq(1100)。
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
20> L1=列表:foldl(fun(X,Acc)->F(X,列表:delete(X,L))++Acc end,[],L)。
[[100,1],
[100,2],
[100|...],
[...]|...]
21>长度(L1)。
9900
22>io:format(“~p~n,[erlang:now()”),list:usort([list:sort(X)| | X list:usort([list:sort(X)| | X

显示执行时间小于0.2秒,第23行上的命令测试其工作。

您是否尝试了
lists:usort([lists:sort(X)| | X F=fun(X,L)->[[X,Y]| Y L=lists:seq(1100)。
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
20> L1=列表:foldl(fun(X,Acc)->F(X,列表:delete(X,L))++Acc end,[],L)。
[[100,1],
[100,2],
[100|...],
[...]|...]
21>长度(L1)。
9900
22>io:format(“~p~n,[erlang:now()”),list:usort([list:sort(X)| | X list:usort([list:sort(X)| | X

显示执行时间小于0.2秒,第23行上的命令将测试其工作情况。

有几种方法。
v1
是最快但最脏的方法:

-module(uniq).

-export([v1/1, v2/1, v3/1, v4/1, gen/1]).

-compile({inline, [s/1]}).

s([X, Y]) when X > Y -> [Y, X];
s(L) -> L.

v1(L) ->
  erase(),
  [put(s(K), ok) || K <- L],
  [K || {K, _} <- erase() ].

v2(L) ->
  sets:to_list(sets:from_list([s(K) || K <- L])).

v3(L) ->
  T = ets:new(set, [private, set]),
  ets:insert(T, [{s(K)} || K <- L]),
  R = [K || {K} <- ets:tab2list(T)],
  ets:delete(T),
  R.

v4(L) ->
  lists:usort([s(K) || K <- L]).

gen(N) ->
  [[random:uniform(100), random:uniform(100)] || _ <- lists:seq(1, N)].

如果将数据复制到单独的堆中或复制到单独的堆中(除非使用二进制),您将失去一些性能,但它仍然是最快的选项。在这种情况下,它需要大约50毫秒的时间,所以仍然是最快的。

有几种方法可以做到这一点。
v1
是最快但最脏的方法:

-module(uniq).

-export([v1/1, v2/1, v3/1, v4/1, gen/1]).

-compile({inline, [s/1]}).

s([X, Y]) when X > Y -> [Y, X];
s(L) -> L.

v1(L) ->
  erase(),
  [put(s(K), ok) || K <- L],
  [K || {K, _} <- erase() ].

v2(L) ->
  sets:to_list(sets:from_list([s(K) || K <- L])).

v3(L) ->
  T = ets:new(set, [private, set]),
  ets:insert(T, [{s(K)} || K <- L]),
  R = [K || {K} <- ets:tab2list(T)],
  ets:delete(T),
  R.

v4(L) ->
  lists:usort([s(K) || K <- L]).

gen(N) ->
  [[random:uniform(100), random:uniform(100)] || _ <- lists:seq(1, N)].

通过将数据复制到单独的堆中或复制到单独的堆中(除非使用二进制文件),您将失去一些性能但是它仍然是最快的选择。在这种情况下,它需要大约50毫秒,所以仍然是最快的。

更好的算法应该使用哈希表或BST作为
unique
中的累加器:通过使用列表,您得到了一个二次时间算法。您能用更有效的数据结构(如集合或平衡sea)替换原始列表吗rch树。两者都可以在创建时自然地识别重复项?更好的算法是在
unique
中使用哈希表或BST作为累加器:通过使用列表,您得到了一个二次时间算法。您是否可以用更有效的数据结构(如集合或平衡搜索树)替换原始列表。或者rally在创建时识别重复项?+1哇,好主意。排序内部列表并使用
usort
2.562s
时更快(总时间包括程序的其余部分)。在将列表传递到
list:usort
之前无需进行预排序。这是一个列表列表。
列表:usort([[1,2],[3,4],[2,1])).
给出了
[[1,2]、[2,1]、[3,4]]
。哦,我知道,给定的列表会被排序,但只需要一对,因此列表会被预先排序。根据第一个列表的大小,可能会有比usort更快的算法。我将对每个解决方案的复杂度以及不同长度的列表进行一点评估。另一种可能是直接生成在没有冗余值的情况下运行列表(如果在应用程序中有意义的话)
pairs(L)->[[X,Y]| | X这同样有效。最低运行时间为
1.437
,5次运行的平均值为
1.453
+1哇,好主意。排序内部列表并使用
usort
2.562s
(包括程序其余部分的总时间)。在将列表传递到
列表之前,无需进行预排序:usort
。这是一个列表列表。
列表:usort([[1,2],[3,4],[2,1]])。
给出
[[1,2],[2,1],[3,4]]
。哦,我知道,给定的列表会被排序,但只需要一对,因此列表会被预先排序。根据第一个列表的大小,可能会有比usort更快的算法。我将对每个解决方案的复杂度以及不同长度的列表进行一点评估。另一种可能是直接生成在没有冗余值的情况下运行列表(如果在应用程序中有意义)
pairs(L)->[[X,Y]| | X这同样有效。最低时间为
1.437
,5次运行的平均时间为
1.453
+1感谢各种方法。我已经尝试了所有算法,其中最快的是
v2
。但是Pascal的答案中的
usort
稍微快一点。不过我没有尝试子进程。Will lo在您的示例中,生成的列表
gen/1
不会创建像[a,b],[b,a]这样的对。整个程序的时间:
v1:2.781
v2:2.687
v3:2.906
v4:2.750
usort\u pascal:2.532
我的初始版本:7.172

-module(uniq).

-export([v1/1, v2/1, v3/1, v4/1, gen/1]).

-compile({inline, [s/1]}).

s([X, Y]) when X > Y -> [Y, X];
s(L) -> L.

v1(L) ->
  erase(),
  [put(s(K), ok) || K <- L],
  [K || {K, _} <- erase() ].

v2(L) ->
  sets:to_list(sets:from_list([s(K) || K <- L])).

v3(L) ->
  T = ets:new(set, [private, set]),
  ets:insert(T, [{s(K)} || K <- L]),
  R = [K || {K} <- ets:tab2list(T)],
  ets:delete(T),
  R.

v4(L) ->
  lists:usort([s(K) || K <- L]).

gen(N) ->
  [[random:uniform(100), random:uniform(100)] || _ <- lists:seq(1, N)].
1> L = uniq:gen(1000000).
...
2> [ element(1, timer:tc(uniq,Alg,[L]))/1000000 || Alg <- [v1, v2, v3, v4]].
[0.243595,1.042272,0.35633,1.309971]
3> [ element(1, timer:tc(uniq,Alg,[L]))/1000000 || Alg <- [v1, v2, v3, v4]].
[0.236856,1.000818,0.359761,1.309743]
4> [ element(1, timer:tc(uniq,Alg,[L]))/1000000 || Alg <- [v1, v2, v3, v4]].
[0.242901,1.039107,0.357476,1.30691]
v1(L) ->
  Self = self(),
  PID = spawn_link(fun() ->
          [put(s(K), ok) || K <- L],
          Self ! {result, self(), [K || {K, _} <- erase() ]}
      end),
  receive
    {result, PID, Result} -> Result
  after 10000 -> error(timout)
  end.