我正在努力在erlang中编写一个递归函数,给出一个元素X和一个列表,从列表中删除元素X并返回新列表。我相信我已经正确地写了它,然而,当我对它进行测试时,我被抛入无限循环中..
delete(_,[]) -> [];
delete(X,[X|_]) -> [];
delete(X,[Y|YS]) ->
if X == Y -> YS;
true -> [Y] ++ delete(X,[YS]) % I believe the infinite loop is a result of this line..
end.
我是erlang的新手(这是我使用该语言的第二个项目),因此对我来说故障排除有点困难,但如果有人能提供一些指导,我们将非常感激。提前谢谢!
答案 0 :(得分:2)
首先,我不知道为什么你需要第二个条款。基本上它会说"如果列表中的第一项与要删除的项匹配,则通过整个列表离开并返回一个空的"。
最简单的方法是从列表开始,使用空列表存储结果。然后,当我们遍历列表中的项目时,我们会添加与结果不匹配的项目,并忽略与我们要删除的项目匹配的项目。这将删除X
中出现的所有List
:
delete(X, List) -> delete(X, List, []). % Provide the same API as before
delete(_,[], Result) -> Result; % If the list is empty we are done.
delete(X,[Y|YS], Result) ->
case X == Y of
true ->
delete(X,[YS], Result);
false ->
delete(X,[Y|YS], Result)
end.
但为什么不使用lists:filter/2
?它使它更简单:
delete(X, List) ->
lists:filter(fun(Item) ->
Item /= X
end, List).
答案 1 :(得分:2)
delete(_,[]) -> []; %% ok removing anything from an empty list gives an empty list
delete(X,[X|_]) -> []; %% big mistake. If you find the element you want to remove on top
%% of the list, you must remove it and continue with the rest of the list
delete(X,[Y|YS]) ->
if X == Y -> YS; %% this will never occurs since you already test this case
%% in the previous clause. An the result should be delete(X,YS), not YS.
true -> [Y] ++ delete(X,[YS]) %% correct
end.
我没有看到你有无限循环的地方,但是第二个句子会使递归调用停止得太早。
所以你的代码应该是:
delete(_,[]) -> [];
delete(X,[X|Rest]) -> delete(X,Rest);
delete(X,[Y|YS]) -> [Y] ++ delete(X,[YS]).
但我会建议使用列表推导来实现非常短的代码和快速执行(这是列表中使用的代码:filter / 2):
delete(X,L) -> [Y || Y <- L, Y =/= X].
% ^ ^ ^
% | | |_ when Y different from X
% | |_________ with all the elements Y from L
% |__________________ make a list
在shell中定义函数,得到:
1> D = fun D(_,[]) -> [];
1> D(X,[X|R]) -> D(X,R);
1> D(X,[Y|R]) -> [Y] ++ D(X,R) end.
#Fun<erl_eval.36.90072148>
2> D(4,[1,2,3,4,5,6]).
[1,2,3,5,6]
3> D1 = fun(X,L) -> [Y || Y <- L, Y =/= X] end.
#Fun<erl_eval.12.90072148>
4> D1(4,[1,2,3,4,5,6]).
[1,2,3,5,6]
5>