我正在尝试创建一条规则,以确定一个列表是否为另一个列表的大小为n的子列表。
isSubgroup/3
isSubgroup(+Subgroup, +Group, +N)
例如,isSubgroup([1, 2, 4], [1, 2, 3, 4, 5], 3)
将返回True
但是,isSubgroup([4, 2, 1], [1, 2, 3, 4, 5], 3)
将返回False
(由于顺序不同)
我想到要检查子组的每个成员是否都是大组的成员,但这会忽略顺序。
这个想法可行吗?
答案 0 :(得分:2)
真的,尝试写一个归纳关系。同时,library(yall)与library(apply)的结合可以使一个衬里:
isSubgroup(S,G,N) :- length(S,N),
foldl({G}/[E,P,X]>>(nth1(X,G,E),X>=P),S,1,_F).
答案 1 :(得分:2)
正如@WillemVanOnsem所建议的,一种归纳解决方案:
subGroups([], []).
subGroups([X|Xs], [X|Ys]):-
subGroups(Xs, Ys).
subGroups(Xs, [_|Ys]):-
subGroups(Xs, Ys).
subGroupsN(Options, N, Solution) :-
length(Solution, N),
subGroups(Solution, Options).
答案 2 :(得分:0)
我们可以通过归纳定义来定义此预测。如果满足以下条件,则Subgroup
是Group
的子组:
Subgroup
是一个空列表; Subgroup
的第一个元素与Group
的第一个元素相同,Subgroup
的其余元素是Group
的其余元素的子组; Subgroup
是Group
其余部分的子组。我们需要相应地更新N
,以便如果Subgroup
为空,则长度为0
:
isSubgroup([], _, 0). %% (1)
isSubgroup([H|TS], [H|TG], N) :- %% (2)
N1 is N-1,
isSubgroup(TS, TG, N1).
isSubgroup(S, [_|TG], N) :- %% (3)
isSubgroup(S, TG, N).
但是,以上结果导致 same 子组的重复true。这是由于我们可以通过多种方式满足谓词这一事实。例如,如果我们调用:
isSubgroup([], [1,2], 0).
然后通过事实(1)满足它,但是最后一个子句(3)也用isSubgroup([], [1], 0).
调用它,然后通过事实(1)来满足它,等等。
我们可以通过限制最后一个子句来避免这种情况:
isSubgroup([], _, 0). %% (1)
isSubgroup([H|TS], [H|TG], N) :- %% (2)
N1 is N-1,
isSubgroup(TS, TG, N1).
isSubgroup([HS|TS], [_|TG], N) :- %% (3)
isSubgroup([HS|TS], TG, N).
以上内容适用于给定的“方向”(所有参数均应扎根,均为“输入”)。但是通常,人们也希望在其他方向上使用谓词。我们也可以实现一个基本版本,该版本在将参数用作“输出”时也基本可以使用,并且仍然使用 tail-call优化(TCO)
:isSubgroup(S, G, N) :-
isSubgroup(S, G, 0, N).
isSubgroup([], _, L, L). %% (1)
isSubgroup([H|TS], [H|TG], L, N) :- %% (2)
L1 is L+1,
isSubgroup(TS, TG, L1, N).
isSubgroup([HS|TS], [_|TG], L, N) :- %% (3)
isSubgroup([HS|TS], TG, L, N).
例如:
?- isSubgroup([1,4,2], G, N).
G = [1, 4, 2|_2974],
N = 3 ;
G = [1, 4, _2972, 2|_2986],
N = 3 ;
G = [1, 4, _2972, _2984, 2|_2998],
N = 3 ;
G = [1, 4, _2972, _2984, _2996, 2|_3010],
N = 3 .
因此,Prolog能够提出[1,4,2]
是其子组的组,并且能够确定该子组的长度N
。
我们也可以反方向查询:
?- isSubgroup(S, [1,4,2], N).
S = [],
N = 0 ;
S = [1],
N = 1 ;
S = [1, 4],
N = 2 ;
S = [1, 4, 2],
N = 3 ;
S = [1, 2],
N = 2 ;
S = [4],
N = 1 ;
S = [4, 2],
N = 2 ;
S = [2],
N = 1 ;
false.
对于给定的组[1,4,2]
,序言可以详尽列举所有可能的子组,以及该子组的长度N
。