Prolog - 检查两个列表是否具有除一个之外的相同元素
Prolog - Check if two lists have the same elements except one
我正在处理两个字符列表,我想检查它们是否具有相同的元素,除了一个位于相同位置,如下所示:
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)).
这是可行的,但有更简单的方法吗?
谢谢。
你是对的,即使你的解决方案有效,它也不是很干净也不能重复使用,因为它只适用于长度为 4 的列表。让我们尝试定义一个适用于任何大小列表的递归谓词.
当一次查看两个列表中的一个元素时,实际上只有两种情况需要考虑:元素相同或不同。
如果它们相同,则意味着两个列表的其余部分必须恰好有一个不同的元素才能成功。这正是我们首先编写的谓词!
compare([H|T1], [H|T2]) :- compare(T1, T2).
现在来看第二种情况。如果列表的第一个元素不同,那么两个列表的其余部分必须完全相同(因为我们已经遇到了不同的元素
compare([H1|T1], [H2|T1]) :- H1 \= H2.
好了,就这些了!现在,您可能会注意到这样的输出:
?- compare([a,b], [a,c]).
true;
false.
这是因为还有一个选择点开放:对于第一个元素,第一个子句匹配,但第二个子句尚未考虑。但在这种情况下,我们知道这两个条款是相互排斥的。所以我们可以加个cut(!
)来保证不留选择点
这也使我们能够简化第二次关闭:如果我们到达这里,我们知道第一个元素不相同,因此无需再次检查。
将它们放在一起,代码变为:
compare([H|T1], [H|T2]) :- !, compare(T1, T2).
compare([_|T], [_|T]).
使用 if_/3
and (=)/3
we can make 单调:
cmp_([X|Xs], [Y|Ys]) :-
if_(X = Y, cmp_(Xs, Ys), Xs = Ys).
我正在处理两个字符列表,我想检查它们是否具有相同的元素,除了一个位于相同位置,如下所示:
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)).
这是可行的,但有更简单的方法吗?
谢谢。
你是对的,即使你的解决方案有效,它也不是很干净也不能重复使用,因为它只适用于长度为 4 的列表。让我们尝试定义一个适用于任何大小列表的递归谓词.
当一次查看两个列表中的一个元素时,实际上只有两种情况需要考虑:元素相同或不同。
如果它们相同,则意味着两个列表的其余部分必须恰好有一个不同的元素才能成功。这正是我们首先编写的谓词!
compare([H|T1], [H|T2]) :- compare(T1, T2).
现在来看第二种情况。如果列表的第一个元素不同,那么两个列表的其余部分必须完全相同(因为我们已经遇到了不同的元素
compare([H1|T1], [H2|T1]) :- H1 \= H2.
好了,就这些了!现在,您可能会注意到这样的输出:
?- compare([a,b], [a,c]).
true;
false.
这是因为还有一个选择点开放:对于第一个元素,第一个子句匹配,但第二个子句尚未考虑。但在这种情况下,我们知道这两个条款是相互排斥的。所以我们可以加个cut(!
)来保证不留选择点
这也使我们能够简化第二次关闭:如果我们到达这里,我们知道第一个元素不相同,因此无需再次检查。
将它们放在一起,代码变为:
compare([H|T1], [H|T2]) :- !, compare(T1, T2).
compare([_|T], [_|T]).
使用 if_/3
and (=)/3
we can make
cmp_([X|Xs], [Y|Ys]) :-
if_(X = Y, cmp_(Xs, Ys), Xs = Ys).