将列表拆分为两个等和erlang列表

将列表拆分为两个等和erlang列表,erlang,erl,Erlang,Erl,我想知道如何将给定的列表拆分为两个列表,使两个列表具有相同的总和。我想通过使用并发来实现这一点。我在二郎做这件事 所以,我在做这样的事情: 阅读列表,如果其总和为偶数,则继续,否则失败。取列表的第一个元素,检查它是否大于总和的一半,如果不大于一半,则将此元素添加到新列表中。接下来,我取列表的第二个元素,检查这个元素和新列表的元素之和,并执行相同的操作。等等这样,当新列表中的和等于第一个列表的和的一半时,它调用另一个函数来发送剩余的元素 -module(piles_hw). -compile(ex

我想知道如何将给定的列表拆分为两个列表,使两个列表具有相同的总和。我想通过使用并发来实现这一点。我在二郎做这件事

所以,我在做这样的事情: 阅读列表,如果其总和为偶数,则继续,否则失败。取列表的第一个元素,检查它是否大于总和的一半,如果不大于一半,则将此元素添加到新列表中。接下来,我取列表的第二个元素,检查这个元素和新列表的元素之和,并执行相同的操作。等等这样,当新列表中的和等于第一个列表的和的一半时,它调用另一个函数来发送剩余的元素

-module(piles_hw).
-compile(export_all).

start([]) -> 0;

start(List) -> 
Total = lists:foldl(fun(X, Sum)-> X+Sum end,0,List), 

if (Total rem 2) == 0 ->
    Total/2, 
    copy_to_list_one([],List,start(List));  
   true ->
    func_fail()
end.

copy_to_list_one(L1,[H|T],X)->
    Y =lists:sum(L1)+H,
    if Y<X ->
        copy_to_list_one(lists:append(L1,[H]),lists:delete(H,[H|T]),X);
       Y==X ->
        take(lists:append(L1,[H]));
      Y>X ->
        copy_to_list_one(L1,lists:delete(H,[H|T]),X)
end;
copy_to_list_one(L1,[],X)->
    copy_func_two([1,2,3,4,19,20,28,14,11],X).
copy_func_two([H|T],X)->
    copy_to_list_one([],lists:append(T,[H]),X).

    take(L3)->    
    io:format("~w",[L3]).

func_fail() ->
    io:format("~n fail ~n").
-模块(桩)。
-编译(全部导出)。
开始([])->0;
开始(列表)->
总计=列表:foldl(乐趣(X,总和)->X+总和结束,0,列表),
如果(总rem 2)==0->
总数/2,
复制到列表中([],列表,开始(列表));
正确->
func_fail()
结束。
复制到列表(L1[H|T],X)->
Y=列表:和(L1)+H,
如果Y
复制到列表(列表:追加(L1[H]),列表:删除(H[H[T]),X);
Y==X->
take(列表:追加(L1[H]);
Y> X->
复制到列表(L1,列表:删除(H[H|T]),X)
结束;
复制到列表(L1,[],X)->
复制函数二([1,2,3,4,19,20,28,14,11],X)。
复制函数二([H | T],X)->
将_复制到_list_one([],list:append(T[H]),X)。
采取(L3)->
io:格式(“~w”,[L3])。
func_fail()->
io:格式(“~n失败~n”)。
但是,通过这种方式,我有时会进入一个无限循环。有人能帮忙吗?

编辑:

帕斯卡是完全正确的:没有一种算法(至少不是我能想到的)可以通过一次运行列表中的一项来求解某些集合。(特别是当列表的一半和等于X*N时,其中X出现在列表中N次。)我最初在这里提出了一个有缺陷的算法


这让我以最无聊的方式兴奋起来,因此这里有一个详尽的算法,涉及到
[{p,(List-p)}| | p对,我有一个非并发的解决方案:

-module(split).

-export([split/1,t_ok/0,t_too_long/0,t_fail/0,t_crash/0]).
%% [EDIT]
%% Don't use this code, it fails with negative integers!


% Exported

%% take a list and split it in 2 list which sum are equals
split(L=[_|_]) ->
    T2 = lists:sum(L),
    {ok, TRef} = timer:send_after(20000,too_long),
    R = case T2 rem 2 of
        1 -> {error,fail};
        0 -> split(tl(L),[hd(L)],[],T2 div 2,hd(L),0)
    end,
    timer:cancel(TRef),
    R.

% test

t_ok() -> split([1,2,3,4,5,6,7]).

t_too_long() -> split(lists:seq(1,3+4*100000)).

t_fail() -> split([2,4,6,10000,8,6]).

t_crash() -> split([]).

% private

split([H|Q],A,B,T,Asf,_Bsf) when H + Asf == T -> {ok,{[H|A],B ++ Q}};                           
split([H|Q],A,B,T,_Asf,Bsf) when H + Bsf == T -> {ok,{A ++ Q,[H|B]}};                           
split([H|Q],A,B,T,Asf,Bsf) when H + Asf > T, H + Bsf < T -> c_split(Q,A,[H|B],T,Asf,Bsf+H);     
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf > T -> c_split(Q,[H|A],B,T,Asf+H,Bsf);     
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf < T -> 
    case c_split(Q,A,[H|B],T,Asf,Bsf+H) of
        {error,fail} -> c_split(Q,[H|A],B,T,Asf+H,Bsf);                                                   
        R -> R                                                                              
    end;  
split([],A,B,_T,_T,_T)-> {ok,{A,B}};                                                                                 
split(_,_,_,_,_,_) -> {error,fail}.

c_split(L,A,B,T,Asf,Bsf) ->
    receive
        too_long -> {error,too_long}
    after 0 ->
        split(L,A,B,T,Asf,Bsf)
    end.
-模块(拆分)。
-导出([split/1,t_ok/0,t_过长/0,t_失败/0,t_崩溃/0])。
%%[编辑]
%%不要使用此代码,它会以负整数失败!
%出口
%%取一个列表,将其拆分为两个和相等的列表
拆分(L=[| |]->
T2=列表:总和(L),
{ok,TRef}=计时器:发送后(20000,太长),
R=第2种情况下的T2 rem
1->{错误,失败};
0->分割(tl(L),[hd(L)],[],T2第2分区,hd(L),0)
完,,
计时器:取消(TRef),
R
%试验
t_ok()->拆分([1,2,3,4,5,6,7])。
t_too_long()->拆分(列表:seq(1,3+4*100000))。
t_fail()->拆分([2,4,610000,8,6])。
t_crash()->拆分([])。
%私人的
当H+Asf==T->{ok,{[H | A],B,T,Asf,{u-Bsf],B++Q}时分裂([H | Q],A,B,T,Asf,{u-Bsf);
当H+Bsf==T->{ok,{A++Q,[H | B]}时拆分([H | Q],A,B,T,_-Asf,Bsf);
当H+Asf>T,H+Bsfc|U分割(Q,A[H|B],T,Asf,Bsf)时分割([H|Q],A,B,T,Asf,Bsf);
当H+AsfT->c|U分割(Q[H|A],B,T,Asf,Bsf)时分割([H|Q],A,B,T,Asf,Bsf);
当H+Asf
案例c|U分割(Q、A、[H|B]、T、Asf、Bsf+H)
{error,fail}->c|u split(Q[H|A],B,T,Asf+H,Bsf);
R->R
结束;
拆分([],A,B,_T,_T,_T)->{ok,{A,B};
拆分(,,,,,,,,->{错误,失败}。
c_分割(L、A、B、T、Asf、Bsf)->
接收
太长->{错误,太长}
0之后->
拆分(L、A、B、T、Asf、Bsf)
结束。
要使它同时运行,您可以通过调用一个函数来替换行
0->split(tl(L),[hd(L)],[],T2 div 2,hd(L),0)
,该函数生成链接多个进程的函数(尽可能多的内核可用)以不同的初始条件启动split/6功能。split/6必须有第7个参数:主进程的Pid,它将在其中返回其答案。主进程等待答案并停止

  • 如果找到解决方案
  • 如果所有进程都找不到一个
  • 如果超时发生

我已经编辑了@Odobenus remark之后的代码(但在[]->{ok,[],[]}:o上仍然失败),并且我还制作了一个并发版本。有趣的是,对于这种问题,我使用了输入列表(a list:seq)有太多的解决方案,我选择的任何开始序列都可以给出一个解决方案,所以并发版本比较慢。

你能给我们看看你到目前为止的代码吗?-module(piles\u-hw)。-compile(export\u-all)。start([])->0;start(List)->nums(length(List)),%def\u-List(List),Total=List:foldl(fun(X,Sum)->X+Sum-end,0,List),if(Total rem 2)==0->Total/2,复制到列表一([],列表,开始(列表));true->func_fail()end.nums(l)->l.复制到列表一(L1[H | T],X)->Y=list:sum(L1)+H,如果Y复制到列表一(列表:追加(L1[H]),列表:删除(H[H | T]),X);Y==X->take(列表:追加(L1[H]);Y>X>复制到列表一(L1,删除),[H | T]),X)结束;请更新您的问题并在那里添加代码。如果使用四个空格缩进,您可以使用代码块,这样代码就更可读。我编辑了我的问题。当无法构造两个相等值的列表时,所需的返回值是多少?嗨,谢谢!!但我有一个关于并发性的问题。如何传递某些部分从一个进程到另一个进程的Icul元素?就像从一个进程发送消息一样,我可以同时包含该进程的某些元素吗?要将元素添加到(比如)在上面的Lpid下运行的进程,您可以执行
Lpid!{self(),{add,H}
。它从那里开始。我建议您在继续之前阅读。从您给出的示例中,在list_loop()中,消息sum和add的发送发生在哪里?我在哪里
-module(split).

-export([split/1,t_ok/0,t_too_long/0,t_fail/0,t_crash/0]).
%% [EDIT]
%% Don't use this code, it fails with negative integers!


% Exported

%% take a list and split it in 2 list which sum are equals
split(L=[_|_]) ->
    T2 = lists:sum(L),
    {ok, TRef} = timer:send_after(20000,too_long),
    R = case T2 rem 2 of
        1 -> {error,fail};
        0 -> split(tl(L),[hd(L)],[],T2 div 2,hd(L),0)
    end,
    timer:cancel(TRef),
    R.

% test

t_ok() -> split([1,2,3,4,5,6,7]).

t_too_long() -> split(lists:seq(1,3+4*100000)).

t_fail() -> split([2,4,6,10000,8,6]).

t_crash() -> split([]).

% private

split([H|Q],A,B,T,Asf,_Bsf) when H + Asf == T -> {ok,{[H|A],B ++ Q}};                           
split([H|Q],A,B,T,_Asf,Bsf) when H + Bsf == T -> {ok,{A ++ Q,[H|B]}};                           
split([H|Q],A,B,T,Asf,Bsf) when H + Asf > T, H + Bsf < T -> c_split(Q,A,[H|B],T,Asf,Bsf+H);     
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf > T -> c_split(Q,[H|A],B,T,Asf+H,Bsf);     
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf < T -> 
    case c_split(Q,A,[H|B],T,Asf,Bsf+H) of
        {error,fail} -> c_split(Q,[H|A],B,T,Asf+H,Bsf);                                                   
        R -> R                                                                              
    end;  
split([],A,B,_T,_T,_T)-> {ok,{A,B}};                                                                                 
split(_,_,_,_,_,_) -> {error,fail}.

c_split(L,A,B,T,Asf,Bsf) ->
    receive
        too_long -> {error,too_long}
    after 0 ->
        split(L,A,B,T,Asf,Bsf)
    end.