Prolog - 检查两个列表除一个元素外是否具有相同的元素

3

我正在处理两个字符列表,我想检查它们是否有相同的元素,除了一个在相同位置上不同,就像这样:

compare([L1,L2,L3,L4],[W1,W2,W3,W4]) :-
((W1 \= L1, W2 = L2, W3 = L3, W4 = L4);
(W1 = L1, W2 \= L2, W3 = L3, W4 = L4);
(W1 = L1, W2 = L2, W3 \= L3, W4 = L4); 
(W1 = L1, W2 = L2, W3 = L3, W4 \= L4)).

这个方法可行,但有更简单的方式吗?
谢谢。
2个回答

4

3
你说得对,尽管你的解决方案有效,但它并不够简洁且不可重用,因为它仅适用于长度为4的列表。让我们尝试定义一个递归谓词,它适用于任何大小的列表。
当一次比较两个列表中的每个元素时,实际上只有两种情况需要考虑:要么这些元素相同,要么它们不同。
如果它们相同,则表示两个列表的其余部分必须恰好有一个不同的元素才能成功。而这正是我们要编写的谓词!
compare([H|T1], [H|T2]) :- compare(T1, T2).

现在来看第二种情况。如果列表的前几个元素不同,那么两个列表的其余部分必须完全相同(因为我们已经遇到了一个不同的元素)。
compare([H1|T1], [H2|T1]) :- H1 \= H2.

那就是全部了!现在,你可能会注意到像这样的输出:
?- compare([a,b], [a,c]).
true;
false.

这是因为仍有一个选择点未关闭:对于第一个元素,第一条子句匹配,但尚未考虑第二条子句。在这种情况下,我们知道两个子句是互斥的。因此,我们可以添加一个剪枝 (!),以确保没有剩余选择点。
这也使我们能够简化第二个关闭:如果我们到达这个点,我们知道第一个元素不相同,所以没有必要再次检查。
将所有内容整合起来,代码如下:
compare([H|T1], [H|T2]) :- !, compare(T1, T2).
compare([_|T], [_|T]).

1
这正是我需要的!谢谢你! - KonaKona
1
工作正常 (+1),但有一个注意事项:两个列表都必须不包含变量,否则代码会表现出非单调性... - repeat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接