gprolog差异列表与重复

时间:2013-01-21 19:32:06

标签: prolog

我必须获得两个整数列表(两个纵坐标)之间的列表差异。 我白了这个:

difference(L,[],L) :- !.
difference([],_,[]) :- !.
difference([],[],W). 
difference([H|T1],[D|T2],T3) :- difference(T1,[D|T2],[H|T3]).
difference([H|T1],[H|T2],T3) :- difference(T1,T2,T3).

但为什么我不能得到我的列表差异? 如果我这样写:

difference([],[],W):- write(X).

和这个例子:

| ?- difference([1,4,4],[1,4],R).    
[4|_27]
它是正确的! 注意如果我有重复的号码我必须显示它!

1 个答案:

答案 0 :(得分:1)

我觉得你的代码很奇怪。例如,你的第三个条款:什么是W?好像你的意思是说:

difference([],[],_).

第二个问题:在第四个条款中,没有什么能阻止H和D成为具有相同绑定的自变量。我怀疑你的意思是这样的:

difference([H|T1],[D|T2],T3) :- H \= D, difference(T1,[D|T2],[H|T3]).

修复这些事情似乎可以修复谓词以给出一个合理的答案:

| ?- difference([1,4,4], [1,4], R).
R = [4]

我认为你的前几个条款试图处理不同类型的基本情况,是吗? E.g:

difference(L, [], L)   % handles the case where the second list is exhausted
difference([], _, [])  % handles the case where the first list is exhausted
difference([], [], W)  % handles the case where the lists are exhausted at the same time

这个问题的一个问题是L = []是一个合法的绑定,所以第一个和第三个子句意思相同。您可以安全地删除第三个,因为它会匹配并在第一个上产生相同的答案。第二个子句更有趣,因为它似乎说无论我们到目前为止做了什么工作,如果第一个列表为空,结果为空。我发现这种可能性有点刺耳 - 你有可能真的想要这两个基本案例吗? :

difference([], L, L).
difference(L, [], L).

我仍然不相信,但在我更好地了解你想要实现的目标之前,我可能无法提供更多帮助。例如,difference([1, 4], [1, 4, 4], R)会发生什么?我假设您可能需要R = [4],但您的代码会生成R = []

另外,我发现它不太可能

difference([],[],W):- write(X).

将是一个有用的调试策略,因为Prolog将为X生成一个新的变量绑定,因为它没有任何内容可供引用。

我对所有更改的最终版本如下所示:

difference(L, [], L) :- !.
difference([], L, L) :- !.
difference([H|T1], [D|T2], T3) :- D \= H, difference(T1, [D|T2], [H|T3]).
difference([H|T1], [H|T2], T3) :- difference(T1, T2, T3).

修改:这是否符合您的要求?

not_in1(X, Left, Right) :- member(X, Left), \+ member(X, Right).

not_in(X, Left, Right) :- not_in1(X, Left, Right).
not_in(X, Left, Right) :- not_in1(X, Right, Left).

differences(Left, Right, Differences) :-
    findall(X, not_in(X, Left, Right), Differences).


?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]

如果是这样,我会尝试让原始代码生成匹配的答案。

编辑2 :好的,所以上面的解决方案的问题是它是O(N ^ 2)。在最坏的情况下(两个完全不同的列表),它必须将列表1中的每个项目与列表2中的每个项目进行比较。它没有利用这两个列表都是有序的事实(我相信这是'纵坐标'的意思)。

结果看起来更像您的原始代码,但您的原始代码没有利用订购商品的事实。这就是为什么第四和第五种情况令人困惑的原因:你应该重复其中一个列表或另一个列表,具体取决于哪个数字更大。更正后的代码如下所示:

differences([], Result, Result).
differences(Result, [], Result).
differences([H|Ls], [H|Rs], Result) :- differences(Ls, Rs, Result).
differences([L|Ls], [R|Rs], [L|Result]) :-
    L < R,
    differences(Ls, [R|Rs], Result).
differences([L|Ls], [R|Rs], [R|Result]) :-
    L > R,
    differences([L|Ls], Rs, Result).

你可以看到这产生与O(N ^ 2)方法相同的结果:

?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]

你是对的,你确实需要两个基本案例。这是任何一个列表的剩余部分成为结果的一部分。据推测,这些值将是最大值(示例中为[5])。

现在我有三个归纳案例:一个针对<,一个针对>,一个针对=。相等的情况很直观:在两个列表上重复,丢弃两个列表的头部。下一个案例基本上说如果左头小于右头,则将其添加到结果中并重复左侧尾部。在这种情况下,权利没有变化。另一种情况是这种情况的镜像。

希望这有帮助!