在Erlang中处理条件的规范方法是什么?

时间:2017-05-30 20:55:22

标签: erlang

我正在使用Erlang中的简单列表函数来学习语法。 一切看起来与我为这些函数的Prolog版本编写的代码非常相似,直到我开始实现“交叉”#。

我能想到的最干净的解决方案:

myIntersection([],_) -> [];
myIntersection([X|Xs],Ys) ->
    UseFirst = myMember(X,Ys),
    myIntersection(UseFirst,X,Xs,Ys).

myIntersection(true,X,Xs,Ys) ->
    [X|myIntersection(Xs,Ys)];
myIntersection(_,_,Xs,Ys) ->
    myIntersection(Xs,Ys).

对我来说,这感觉就像一个黑客。有没有更规范的方法来处理这个问题?通过“规范”,我的意思是一种符合Erlang设计精神的实现。

注意:此问题的本质是用户定义的谓词函数的条件处理。我要求有人指点我的图书馆功能。谢谢!

3 个答案:

答案 0 :(得分:2)

我喜欢这个:

inter(L1,L2) -> inter(lists:sort(L1),lists:sort(L2),[]).

inter([H1|T1],[H1|T2],Acc) -> inter(T1,T2,[H1|Acc]);
inter([H1|T1],[H2|T2],Acc) when H1 < H2 -> inter(T1,[H2|T2],Acc);
inter([H1|T1],[_|T2],Acc) -> inter([H1|T1],T2,Acc);
inter([],_,Acc) -> Acc;
inter(_,_,Acc) -> Acc.

它给出了确切的交集:

inter("abcd","efgh") -> []
inter("abcd","efagh") -> "a"
inter("abcd","efagah") -> "a"
inter("agbacd","eafagha") -> "aag"

如果您希望某个值只出现一次,只需将lists:sort/1函数中的一个替换为lists:usort/1

修改

正如@ 9000所说,一个条款没用:

inter(L1,L2) -> inter(lists:sort(L1),lists:sort(L2),[]).

inter([H1|T1],[H1|T2],Acc) -> inter(T1,T2,[H1|Acc]);
inter([H1|T1],[H2|T2],Acc) when H1 < H2 -> inter(T1,[H2|T2],Acc);
inter([H1|T1],[_|T2],Acc) -> inter([H1|T1],T2,Acc);
inter(_,_,Acc) -> Acc.

给出相同的结果,

inter(L1,L2) -> inter(lists:usort(L1),lists:sort(L2),[]).

inter([H1|T1],[H1|T2],Acc) -> inter(T1,T2,[H1|Acc]);
inter([H1|T1],[H2|T2],Acc) when H1 < H2 -> inter(T1,[H2|T2],Acc);
inter([H1|T1],[_|T2],Acc) -> inter([H1|T1],T2,Acc);
inter(_,_,Acc) -> Acc.

删除输出中的任何副本。

如果您知道输入列表中没有重复值,我认为

inter(L1,L2) -> [X || X <- L1, Y <- L2, X == Y].

是更短的代码解决方案,但速度要慢得多(1秒用于评估10个元素的2个列表的交集,而之前的解决方案为16毫秒,O(2)复杂度与@David Varela提案相当;比率为70s与280ms相比,2个100000个元素列表!,我猜有更大的列表会耗尽内存的风险很高)

答案 1 :(得分:1)

规范方式(&#34;规范&#34;如&#34; SICP&#34;)是使用累加器。

myIntersection(A, B) -> myIntersectionInner(A, B, []).

myIntersectionInner([], _, Acc) -> Acc;
myIntersectionInner(_, [], Acc) -> Acc;
myIntersectionInner([A|As], B, Acc) -> 
  case myMember(A, Bs) of
    true -> 
      myIntersectionInner(As, Bs, [A|Acc]);
    false -> 
      myIntersectionInner(As, Bs, [Acc]);
  end.

如果两个输入中都存在重复项,则此实现当然会产生重复项。这可以通过调用myMember(A, Acc)来解决,只有追加A才会导致结果为负。

我对近似语法道歉。

答案 2 :(得分:0)

虽然我很欣赏所建议的有效实现,但我的目的是更好地理解Erlang的实现。作为初学者,我认为@ 7stud的评论,特别是http://erlang.org/pipermail/erlang-questions/2009-December/048101.html,是最有启发性的。实质上,&#39; case&#39;函数中的模式匹配使用相同的机制,但为了清楚起见,应该首选函数。

在一个真实的系统中,我会选择@ Pascal的一个实现;取决于是否相交&#39;做了任何繁重的工作。