我正在使用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设计精神的实现。
注意:此问题的本质是用户定义的谓词函数的条件处理。我不要求有人指点我的图书馆功能。谢谢!
答案 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;做了任何繁重的工作。