大小为n的列表的Prolog子组

时间:2019-01-18 14:26:25

标签: prolog

我正在尝试创建一条规则,以确定一个列表是否为另一个列表的大小为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(由于顺序不同)

我想到要检查子组的每个成员是否都是大组的成员,但这会忽略顺序。

这个想法可行吗?

3 个答案:

答案 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)

我们可以通过归纳定义来定义此预测。如果满足以下条件,则SubgroupGroup的子组:

  1. Subgroup是一个空列表;
  2. Subgroup的第一个元素与Group的第一个元素相同,Subgroup的其余元素是Group的其余元素的子组;
  3. SubgroupGroup其余部分的子组。

我们需要相应地更新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