集相等

时间:2019-06-22 19:35:57

标签: prolog swi-prolog

任何人都可以帮助我完成以下任务:我需要定义一个谓词eq_set,如果集合S1S2的元素数量相等,则谓词eq_set成功。

但是仅当它们的编号和顺序完全相同时,它才有效。我想创建一个显示所有品种并且不考虑顺序的代码。请你帮我一下吗?

我写道:

eq_set([],[]).
eq_set([H|T],[H|T1]) :-
    eq_set(T,T1).

但是仅当它们的编号和顺序完全相同时,它才有效。我想创建一个显示所有品种并且不考虑顺序的代码。

与该赋值最接近的翻译是保加利亚语:“定义谓词eq_set,如果集合(S1,S2)重合,则谓词eq_set成功。

4 个答案:

答案 0 :(得分:2)

真的真的取决于谓词的使用方式。

假设一个“集合”确实是一个Prolog列表,没有重复项,但没有任何特定顺序;那么如果它们彼此置换,则该表示中的两个集合“重合”。换句话说,将eq_set/2定义为:

eq_set(A, B) :-
    my_permutation(A, B).

,仅使用permutation/2的教科书定义,该定义使用select/3的教科书定义(请参见Sterling和Shapiro撰写的“序言的艺术(第二版)”,第67-9页):< / p>

my_permutation([], []).
my_permutation(Xs, [Y|Ys]) :-
    my_select(Y, Xs, Xs0),
    my_permutation(Xs0, Ys).

my_select(X, [X|Xs], Xs).
my_select(X, [Y|Ys], [Y|Zs]) :-
    my_select(X, Ys, Zs).

(我重命名了这些名称只是为了确保我没有使用标准库定义; SWI-Prolog在select/3中同时包含permutation/2autoloaded library(lists);这些定义基本上是相同的,但它们会对参数进行一些运行时类型检查。)

这里是使用方式:

?- eq_set([1,2,3], [2,3,1]).
true ;
false.

?- eq_set([1,2,3], S).
S = [1, 2, 3] ;
S = [1, 3, 2] ;
S = [2, 1, 3] ;
S = [2, 3, 1] ;
S = [3, 1, 2] ;
S = [3, 2, 1] ;
false.

?- eq_set([1,2,3], [1,2]).
false.

?- eq_set(A, B).
A = B, B = [] ;
A = B, B = [_4480] ;
A = B, B = [_4480, _4492] ;
...

我不确定最后一个查询是否有用。您可以强制其按“集合”的大小递增顺序枚举解决方案,如下所示:

?- length(S1, _), eq_set(S1, S2), numbervars(S1).
S1 = S2, S2 = [] ;
S1 = S2, S2 = [A] ;
S1 = S2, S2 = [A, B] ;
S1 = [A, B],
S2 = [B, A] ;
S1 = S2, S2 = [A, B, C] ;
S1 = [A, B, C],
S2 = [A, C, B] ;
S1 = [A, B, C],
S2 = [B, A, C] ;
S1 = [A, B, C],
S2 = [B, C, A] ;
S1 = [A, B, C],
S2 = [C, A, B] ;
S1 = [A, B, C],
S2 = [C, B, A] ;
S1 = S2, S2 = [A, B, C, D] .

(不必担心numbervars,它只是为集合中的所有自由变量赋予易读的名称。请记住,统一两个自由变量会使它们成为同一变量。)

这是一个起点,但也许已经足够了。最明显的遗漏是它不需要将参数作为没有重复的列表。定义此方法的一种方法是要求每个元素都与所有其他元素不同。由于“与众不同”是可交换的,因此可以这样定义:

is_set([]).
is_set([X|Xs]) :-
    all_different(Xs, X),
    is_set(Xs).

all_different([], _).
all_different([Y|Ys], X) :-
    dif(X, Y),
    all_different(Ys, X).

这使用dif/2,这是一个广泛使用的谓词(但是您的Prolog是否拥有它?)。

对于最后一个,我们可能会使用maplist

is_set([]).
is_set([X|Xs]) :-
    maplist(dif(X), Xs).
    is_set(Xs).

答案 1 :(得分:1)

您称它们为“集合”,但您使用的数据结构是一个列表。对两个列表进行排序最简单:

eq_set(A, B) :-
    % prerequisites: A and B are lists without duplicates
    sort(A, S),
    sort(B, S).

如果您想要更复杂的内容(出于某种原因),则需要更加具体。

具有以下定义:

?- eq_set([a,b,c], [a,b]).
false. % OK

?- eq_set([a,b,c], [a,b,c]).
true. % OK

?- eq_set([a,c,b], [a,b,c]).
true. % OK

?- eq_set([a,a,b], [a,b,b]).
true. % Not sure....

答案 2 :(得分:1)

您的解决方案非常接近。

我们有两种情况 1)第一个列表参数较大 2)第二个列表参数更大

如果您已经知道哪个更大,就可以做

%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).

因此,一个非常简单的解决方案却是非常理想的:

%in case the right one is longer
eq_set_right([],_).
eq_set_right([H|T], X):- member(H,X), eq_set_right(T,X).

%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).

%both cases, equal length is also included here
eq_set(X,Y):- eq_set_left(X,Y).
eq_set(X,Y):- eq_set_right(X,Y).

eq_set(X,Y)为真,如果X是Y的子集,Y是X的子集或者它们相等

答案 3 :(得分:0)

一个 set 定义为 distinct 事物的集合,其中顺序并不重要,也就是说,集合{a,b,c}{b,a,c}完全相同。

由此可以说,如果两个集合中的任何一个都不包含在另一个中也找不到的元素,则这两个集合是相同的(或者相反,如果两个集合中的任何一个都包含在另一个元素中都找不到的元素,则两个集合不相同。< / p>

由此,人们可以简单地说:

eq_set(Xs,Ys) :-
   findall( (Xs,Ys) , ( member(X,Xs), \+ member(X,Ys) ), [] ),
   findall( (Xs,Ys) , ( member(Y,Ys), \+ member(Y,Xs) ), [] )
   .

或者,如果您不想使用内置的findall/3

eq_set(Xs,Ys) :-
  a_not_in_b( Xs , Ys , [] ) ,
  a_not_in_b( Ys , Xs , [] ) .

a_not_in_b( []     , [] , [] ) .
a_not_in_b( [A|As] , Bs , Xs ) :- member(A,Bs) , a_not_in_b( As, Bs,    Xs  ) .
a_not_in_b( [A|As] , Bs , Xs ) :-                a_not_in_b( As, Bs, [A|Xs] ) .

请注意,这两者的性能大致都为O(N 2 )。如果所讨论的集合很大,则可能需要先对每个集合排序,然后合并两个排序的列表,以识别两个集合都不通用的那些元素:

eq_set(Xs,Ys) :-
  sort(Xs,X1),
  sort(Ys,Y1),
  X1 == Y1.