Erlang 二郎;无重复列表

Erlang 二郎;无重复列表,erlang,Erlang,我正在做一些可怕的事情,但我不知道如何让它变得更好 我正在形成一个名为SomeList的列表中元素的所有成对和,但我不想看到重复的元素,我想我想要所有可能的成对和: sets:to_list(sets:from_list([A+B || A <- SomeList, B <- SomeList])) SomeList不包含重复项 这是可行的,但效率非常低,因为集合转换之前的原始列表非常庞大 有更好的方法吗?此模块允许您在使用列表理解、集合或ets时比较执行时间。当然,您可以在此比较

我正在做一些可怕的事情,但我不知道如何让它变得更好

我正在形成一个名为SomeList的列表中元素的所有成对和,但我不想看到重复的元素,我想我想要所有可能的成对和:

sets:to_list(sets:from_list([A+B || A <- SomeList, B <- SomeList]))
SomeList不包含重复项

这是可行的,但效率非常低,因为集合转换之前的原始列表非常庞大


有更好的方法吗?

此模块允许您在使用列表理解、集合或ets时比较执行时间。当然,您可以在此比较中添加其他函数:

-module(pairwise).

-export([start/2]).

start(Type, X) ->
    L = lists:seq(1, X),
    timer:tc(fun do/2, [Type, L]).

do(compr, L) ->
    sets:to_list(sets:from_list([A+B || A <- L, B <- L]));

do(set, L) ->
    F = fun(Sum, Set) -> sets:add_element(Sum, Set) end,
    R = fun(Set) -> sets:to_list(Set) end,
    do(L, L, sets:new(), {F, R});

do(ets, L) ->
    F = fun(Sum, Tab) -> ets:insert(Tab, {Sum}), Tab end,
    R = fun(Tab) ->
                Fun = fun({X}, Acc) -> [X|Acc] end,
                Res = ets:foldl(Fun, [], Tab),
                ets:delete(Tab),
                Res
        end,
    do(L, L, ets:new(?MODULE, []), {F, R}).

do([A|AT], [B|BT], S, {F, _} = Funs) -> do([A|AT], BT, F(A+B, S), Funs);
do([_AT], [], S, {_, R}) -> R(S);
do([_A|AT], [], S, Funs) -> do(AT, AT, S, Funs).
最后一行是比较所有函数返回相同的结果,但排序不同


每个结果元组中的第一个数字是从计时器返回的执行时间:tcfun do/2,[Type,L]。。在本例中,列表理解为282,集合为155,ets为96。

此模块允许您比较使用列表理解、集合或ets时的执行时间。当然,您可以在此比较中添加其他函数:

-module(pairwise).

-export([start/2]).

start(Type, X) ->
    L = lists:seq(1, X),
    timer:tc(fun do/2, [Type, L]).

do(compr, L) ->
    sets:to_list(sets:from_list([A+B || A <- L, B <- L]));

do(set, L) ->
    F = fun(Sum, Set) -> sets:add_element(Sum, Set) end,
    R = fun(Set) -> sets:to_list(Set) end,
    do(L, L, sets:new(), {F, R});

do(ets, L) ->
    F = fun(Sum, Tab) -> ets:insert(Tab, {Sum}), Tab end,
    R = fun(Tab) ->
                Fun = fun({X}, Acc) -> [X|Acc] end,
                Res = ets:foldl(Fun, [], Tab),
                ets:delete(Tab),
                Res
        end,
    do(L, L, ets:new(?MODULE, []), {F, R}).

do([A|AT], [B|BT], S, {F, _} = Funs) -> do([A|AT], BT, F(A+B, S), Funs);
do([_AT], [], S, {_, R}) -> R(S);
do([_A|AT], [], S, Funs) -> do(AT, AT, S, Funs).
最后一行是比较所有函数返回相同的结果,但排序不同


每个结果元组中的第一个数字是从计时器返回的执行时间:tcfun do/2,[Type,L]。。在本例中,列表理解为282,集合为155,ets为96。

此解决方案保持相对快速,并尽可能多地使用预先编写的库代码

注意,我在这里使用lists:zip/2而不是numeric+,只是为了说明这种方法适用于唯一列表的任何类型的非重复排列。你可能只关心算术,但如果你想要更多,这可以做到

-export([permute_unique/1]).
permute_unique([]) ->
    [];
permute_unique([A|Ab]) ->
    lists:zip(lists:duplicate(length(Ab)+1, A), [A|Ab])
    ++
    permute_unique(Ab).

%to sum integers, replace the lists:zip... line with
%   [B+C || {B,C} <- lists:zip(lists:duplicate(length(Ab)+1, A), [A|Ab])]
%to perform normal arithmetic and yield a numeric value for each element

我不确定你认为什么是巨大的——你将在n个原始元素的唯一列表中,在置换列表中得到n*n+1/2个元素,因此这会变得非常快。 我做了一些基本的性能测试,使用Intel Haswell Core i7@4GHz,32GB内存,运行Erlang/OTP 17 64位

根据计时器:tc/1,列表中的5001个元素花费了2到5秒

列表中的10001个元素花费了15到17秒,需要大约9GB的内存。这将生成一个包含50015001个元素的列表

列表中的15001个元素耗时21到25秒,需要19GB内存


列表中的20001个元素在一次运行中花费了49秒,在大约30GB的内存中达到峰值,结果中有大约2亿个元素。这就是我所能测试的极限。

此解决方案使它保持相对较快的速度,并尽可能多地使用预先编写的库代码

注意,我在这里使用lists:zip/2而不是numeric+,只是为了说明这种方法适用于唯一列表的任何类型的非重复排列。你可能只关心算术,但如果你想要更多,这可以做到

-export([permute_unique/1]).
permute_unique([]) ->
    [];
permute_unique([A|Ab]) ->
    lists:zip(lists:duplicate(length(Ab)+1, A), [A|Ab])
    ++
    permute_unique(Ab).

%to sum integers, replace the lists:zip... line with
%   [B+C || {B,C} <- lists:zip(lists:duplicate(length(Ab)+1, A), [A|Ab])]
%to perform normal arithmetic and yield a numeric value for each element

我不确定你认为什么是巨大的——你将在n个原始元素的唯一列表中,在置换列表中得到n*n+1/2个元素,因此这会变得非常快。 我做了一些基本的性能测试,使用Intel Haswell Core i7@4GHz,32GB内存,运行Erlang/OTP 17 64位

根据计时器:tc/1,列表中的5001个元素花费了2到5秒

列表中的10001个元素花费了15到17秒,需要大约9GB的内存。这将生成一个包含50015001个元素的列表

列表中的15001个元素耗时21到25秒,需要19GB内存

列表中的20001个元素在一次运行中花费了49秒,在大约30GB的内存中达到峰值,结果中有大约2亿个元素。这就是我可以测试的极限。

您可以简单地使用列表:usort/1

list:usort[X+Y | | X您可以简单地使用list:usort/1


列表:usort[X+Y | | X一种有效的方法是使用foldl而不是列表理解,因为在这种情况下,您需要在每个步骤上添加一个状态

设置:到列表 列表:foldlfunA,S1-> 列表:foldlfunB,S2-> 集合:添加元素A+B,S2 完,S1,SomeListA 结束,集合:新建,SomeListB。
一种有效的方法是使用foldl而不是列表理解,因为在这种情况下,您需要在每个步骤上添加一个状态

设置:到列表 列表:foldlfunA,S1-> 列表:foldlfunB,S2-> 集合:添加元素A+B,S2 完,S1,SomeListA 结束,集合:新建,SomeListB。
A和/或B可以有重复项吗?在不知道类型的情况下,我不确定我的下一个问题是否有意义,但如果两个元素A+B解析为另两个元素c+d也可以存在的某个元素,那么该重复项是允许的,因为它来自两个不同的源对,还是不允许的,因为它解析为重复值?我编辑了我的问题要回答您的问题,在返回的最终列表中,我不需要重复项。我需要集合的结果:to_listsets:
来自_listA。也就是说,如果A中的两个元素具有相同的值,无论该值是如何得到的,我都希望其中一个元素消失。您可以发布一个示例输入和输出,其中包含列表中的两个元素吗?我基本上不清楚的是,您谈论的是成对和,但您的代码生成了一个成对和的唯一组合列表。成对和似乎是所有对Ai Aj的和,其中iCan A和/或B有重复项?在不知道类型的情况下,我不确定我的下一个问题是否有意义,但如果两个元素a+b解析为其他两个元素c+d也可能存在的某个元素,那么该重复是允许的,因为它来自两个不同的源对,还是不允许的,因为它解析为重复值?我编辑了我的问题以回答您的问题,在返回的最终列表中,我不希望重复。我想要集合:to_listset:from_listA的结果。也就是说,如果A中的两个元素具有相同的值,无论该值是如何得到的,我都希望其中一个元素消失。您可以发布一个示例输入和输出,其中包含列表中的两个元素吗?我基本上不清楚的是,您谈论的是成对和,但您的代码生成了一个成对和的唯一组合列表。两两求和似乎是所有对Ai Aj的和