Prolog - 检查第二个列表是否包含第一个列表中的所有偶数
Prolog - Check if second list has all even numbers from the first list
我正在尝试在 Prolog 中编写一个规则,该规则将首先检查第二个列表中的所有元素是否都包含在第一个列表中以及第二个列表中的所有元素是否为偶数。
因此,例如以下查询:
evenSubList([5, 6, 7, 8], [6, 8]). -> True
evenSubList([5, 6, 7, 8], [6, 7, 8]). -> no
evenSubList([5, 6, 7, 8], X). -> X = [6, 8]
evenSubList([6, 7, 8], [6, 8]). -> True
evenSubList([6, 8], [6, 8]). -> True
当我查询我当前的代码时,只有当两个列表都只有偶数时它才有效。第一个列表不允许有任何奇数。我也尝试过使用内置的子列表规则,但没有成功。我知道问题出在我的第二个定义中,两个列表中的头部不同,但我不确定我做错了什么。
evenSubList([X | _], [X]) :- % base case gets hit if second list only has one element
mod(X, 2) =:= 0.
evenSubList([X | Y], [Z | T]) :- % If first element of both lists are different
evenSubList(Y, [Z]),
evenSubList(Y, T).
evenSubList([X | Y], [X | Z]) :- % If both heads are the same
mod(X, 2) =:= 0,
evenSubList(Y, Z).
你的想法是对的,只是你的情况是头部不一样,你试图同时做两件事并且绊倒了自己,因为最终你会得到一个空列表并且那个将 return 错误。有一个更简单的解决方案。
你从尾巴开始,Y
,然后遍历比较它与头部 Z
,但如果两个头部相同,你将有一个空调用,这将导致输出为 no
.
对于第二次递归调用 evenSubList(Y, T)
,如果 T
比 Y
短,您将遇到空列表问题。
您想做这样的事情,其中第一个列表变小,第二个列表保持相同大小,并将第一个列表中的每个元素与第二个列表作为一个整体进行比较,直到或除非遇到其他情况,您会知道取第二个列表的尾部是安全的。
evenSubList([X], [X]) :-
mod(X, 2) =:= 0.
evenSubList([X | Y], [X | Z]) :-
mod(X, 2) =:= 0,
filterevens(Y, Z).
evenSubList([X | Y], [Z | T]) :-
evenSubList(Y, [Z | T]).
这很简单:
even_contains(LstFull, LstEven) :-
include(is_even, LstFull, LstEven).
is_even(N) :-
0 is N mod 2.
结果swi-prolog:
?- even_contains([5, 6, 7, 8], [6, 8]).
true.
?- even_contains([5, 6, 7, 8], [6, 7, 8]).
false.
?- even_contains([5, 6, 7, 8], X).
X = [6,8].
?- even_contains([6, 7, 8], [6, 8]).
true.
?- even_contains([6, 8], [6, 8]).
true.
我正在尝试在 Prolog 中编写一个规则,该规则将首先检查第二个列表中的所有元素是否都包含在第一个列表中以及第二个列表中的所有元素是否为偶数。
因此,例如以下查询:
evenSubList([5, 6, 7, 8], [6, 8]). -> True
evenSubList([5, 6, 7, 8], [6, 7, 8]). -> no
evenSubList([5, 6, 7, 8], X). -> X = [6, 8]
evenSubList([6, 7, 8], [6, 8]). -> True
evenSubList([6, 8], [6, 8]). -> True
当我查询我当前的代码时,只有当两个列表都只有偶数时它才有效。第一个列表不允许有任何奇数。我也尝试过使用内置的子列表规则,但没有成功。我知道问题出在我的第二个定义中,两个列表中的头部不同,但我不确定我做错了什么。
evenSubList([X | _], [X]) :- % base case gets hit if second list only has one element
mod(X, 2) =:= 0.
evenSubList([X | Y], [Z | T]) :- % If first element of both lists are different
evenSubList(Y, [Z]),
evenSubList(Y, T).
evenSubList([X | Y], [X | Z]) :- % If both heads are the same
mod(X, 2) =:= 0,
evenSubList(Y, Z).
你的想法是对的,只是你的情况是头部不一样,你试图同时做两件事并且绊倒了自己,因为最终你会得到一个空列表并且那个将 return 错误。有一个更简单的解决方案。
你从尾巴开始,Y
,然后遍历比较它与头部 Z
,但如果两个头部相同,你将有一个空调用,这将导致输出为 no
.
对于第二次递归调用 evenSubList(Y, T)
,如果 T
比 Y
短,您将遇到空列表问题。
您想做这样的事情,其中第一个列表变小,第二个列表保持相同大小,并将第一个列表中的每个元素与第二个列表作为一个整体进行比较,直到或除非遇到其他情况,您会知道取第二个列表的尾部是安全的。
evenSubList([X], [X]) :-
mod(X, 2) =:= 0.
evenSubList([X | Y], [X | Z]) :-
mod(X, 2) =:= 0,
filterevens(Y, Z).
evenSubList([X | Y], [Z | T]) :-
evenSubList(Y, [Z | T]).
这很简单:
even_contains(LstFull, LstEven) :-
include(is_even, LstFull, LstEven).
is_even(N) :-
0 is N mod 2.
结果swi-prolog:
?- even_contains([5, 6, 7, 8], [6, 8]).
true.
?- even_contains([5, 6, 7, 8], [6, 7, 8]).
false.
?- even_contains([5, 6, 7, 8], X).
X = [6,8].
?- even_contains([6, 7, 8], [6, 8]).
true.
?- even_contains([6, 8], [6, 8]).
true.