任何人都可以帮助我完成以下任务:我需要定义一个谓词eq_set,如果集合S1
和S2
的元素数量相等,则谓词eq_set成功。
但是仅当它们的编号和顺序完全相同时,它才有效。我想创建一个显示所有品种并且不考虑顺序的代码。请你帮我一下吗?
我写道:
eq_set([],[]).
eq_set([H|T],[H|T1]) :-
eq_set(T,T1).
但是仅当它们的编号和顺序完全相同时,它才有效。我想创建一个显示所有品种并且不考虑顺序的代码。
与该赋值最接近的翻译是保加利亚语:“定义谓词eq_set,如果集合(S1,S2)重合,则谓词eq_set成功。
答案 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/2
和autoloaded 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.