有没有办法只 select PROLOG 中列表的第一个和最后一个元素?
Is there a way to select only the first and last element of a list in PROLOG?
我正在尝试编写一个谓词,如果 X 是 Y 的子列表,则该谓词为真,而不考虑 Y 的第一项和最后一项。例如,查询 listWithinList([b,c,d ],[a,b,c,d,e]) 将 return 为真,但查询 listWithinList([b,c,d,e],[a,b,c,d,e]) 将产生错误,因为 Y 的最后一个元素 e 不应该是 X 的一部分。
目前我有
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
但我不确定如何更改代码以使其具有相同的技巧,但不考虑 Y 的第一项和最后一项。
由于列表在 Prolog 中的表示方式,您可以通过将第一个元素解构为头和尾并将结果与尾统一来轻松删除第一个元素,如下所示:
tail([_|L], L).
成功时,谓词将第二个参数与第一个参数的尾部统一起来。
要删除最后一个元素,您可以说您的输入列表是将前缀附加到一个元素列表(其值不重要)的结果:
butlast(List, Prefix) :-
append(Prefix, [_LastValue], List).
您可以将它们结合起来以移除双肢:
chop(List, Middle):
tail(List, Tail),
butlast(Tail, Middle).
这是我的方法:
首先:创建当删除第一个字母和最后一个字母时可接受的列表的所有组合。
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
第一次追加从列表中删除第一个元素,第二次追加从列表中删除最后一个元素。 List的组合存储在S.
其次:我们使用相同的谓词来检查M是否与S中的任何组合相同。
same(L1,L2):-
L1==L2.
将代码放在一起:
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
( same(M,S)->write(S),
write('This combination is correct.') ).
same(L1,L2):-
L1==L2.
示例:
?-listWithinList([b,c,d],[a,b,c,d,e]).
[b, c, d]This combination is correct.
1true
false
?-listWithinList([b,c,d,e],[a,b,c,d,e]).
false
?-listWithinList([a,b,c,d,e],[a,b,c,d,e]).
false
当您在 append
的参数中写入 _
时,它指的是任意列表。如此随意以至于它的长度也是任意的。
例如:
?- append(_, Suffix, [a, b, c]).
Suffix = [a, b, c] ;
Suffix = [b, c] ;
Suffix = [c] ;
Suffix = [] ;
false.
这里的_
可以代表列表[]
、[a]
、[a, b]
、[a, b, c]
中的任意一个。但我不需要告诉你这个。如果您给匿名变量 _
一个合适的名称,Prolog 可以告诉您:
?- append(Prefix, Suffix, [a, b, c]).
Prefix = [],
Suffix = [a, b, c] ;
Prefix = [a],
Suffix = [b, c] ;
Prefix = [a, b],
Suffix = [c] ;
Prefix = [a, b, c],
Suffix = [] ;
false.
相比之下,术语[_]
不代表任意列表。它代表一个绝对只有一个元素的列表。该元素(表示为 _
)是任意的。
例如:
?- append([_], Suffix, [a, b, c]).
Suffix = [b, c].
或者,再次使用适当的变量名,以便我们可以看到绑定:
?- append([X], Suffix, [a, b, c]).
X = a,
Suffix = [b, c].
这就是说问题的定义:
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
接近正确。但是 _
的两种用法都不会“删除”一个元素。他们每个“删除”任意数量的元素。所以你不只是得到列表的中间:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [] ;
Middle = [a] ;
Middle = [a, b] ;
Middle = [a, b, c] ;
Middle = [a, b, c, d] ;
Middle = [a, b, c, d, e] ;
Middle = [] ;
Middle = [b] ;
Middle = [b, c] ;
Middle = [b, c, d] ;
Middle = [b, c, d, e] ;
Middle = [] ;
Middle = [c] ;
Middle = [c, d] ;
Middle = [c, d, e] ;
Middle = [] ;
Middle = [d] ;
Middle = [d, e] ;
Middle = [] ;
Middle = [e] ;
Middle = [] ;
false.
如果我们想从前面和后面“删除”恰好一个元素的列表,我们必须写 [_]
:
listWithinList(X, Y) :-
append([_], Y2, Y),
append(X, [_], Y2).
现在的行为如下:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [b, c, d] ;
false.
此外,请注意 [_]
和 [_|_]
之间的区别。前者代表 exactly 一个元素的列表。后者代表 一个或多个 元素的列表。在这种情况下,您不想“删除”多个元素,因此使用 [_|_]
,就像其他答案之一所暗示的那样,绝对是胡说八道。
最后,Prolog 可以向我们建议进一步简化:
?- append([X], Xs, Ys).
Ys = [X|Xs].
附加一个单元素列表 [X]
和一个任意列表 Xs
给出一个列表,我们也可以在不使用 append
的情况下将其写为 [X | Xs]
。因此不需要 append
调用之一。我可能会这样写这个谓词:
list_middle(List, Middle) :-
append([_First | Middle], [_Last], List).
并像这样使用它:
?- list_middle([a, b, c, d, e], Middle).
Middle = [b, c, d] ;
false.
或者像这样:
?- list_middle(List, [1, 2, 3]).
List = [_2658, 1, 2, 3, _2664].
对于此类任务,语法非常直观。简单描述一下我们有什么:
list_within(Xs, Ys) :-
phrase(( [_First], seq(Ys), [_Last] ), Xs).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
即首先是元素_First
,然后是序列Ys
,最后是元素_Last
。
我正在尝试编写一个谓词,如果 X 是 Y 的子列表,则该谓词为真,而不考虑 Y 的第一项和最后一项。例如,查询 listWithinList([b,c,d ],[a,b,c,d,e]) 将 return 为真,但查询 listWithinList([b,c,d,e],[a,b,c,d,e]) 将产生错误,因为 Y 的最后一个元素 e 不应该是 X 的一部分。
目前我有
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
但我不确定如何更改代码以使其具有相同的技巧,但不考虑 Y 的第一项和最后一项。
由于列表在 Prolog 中的表示方式,您可以通过将第一个元素解构为头和尾并将结果与尾统一来轻松删除第一个元素,如下所示:
tail([_|L], L).
成功时,谓词将第二个参数与第一个参数的尾部统一起来。
要删除最后一个元素,您可以说您的输入列表是将前缀附加到一个元素列表(其值不重要)的结果:
butlast(List, Prefix) :-
append(Prefix, [_LastValue], List).
您可以将它们结合起来以移除双肢:
chop(List, Middle):
tail(List, Tail),
butlast(Tail, Middle).
这是我的方法:
首先:创建当删除第一个字母和最后一个字母时可接受的列表的所有组合。
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
第一次追加从列表中删除第一个元素,第二次追加从列表中删除最后一个元素。 List的组合存储在S.
其次:我们使用相同的谓词来检查M是否与S中的任何组合相同。
same(L1,L2):-
L1==L2.
将代码放在一起:
listWithinList(M,L):-
append([_|_],L2,L),
append(S,[_|_],L2),
( same(M,S)->write(S),
write('This combination is correct.') ).
same(L1,L2):-
L1==L2.
示例:
?-listWithinList([b,c,d],[a,b,c,d,e]).
[b, c, d]This combination is correct.
1true
false
?-listWithinList([b,c,d,e],[a,b,c,d,e]).
false
?-listWithinList([a,b,c,d,e],[a,b,c,d,e]).
false
当您在 append
的参数中写入 _
时,它指的是任意列表。如此随意以至于它的长度也是任意的。
例如:
?- append(_, Suffix, [a, b, c]).
Suffix = [a, b, c] ;
Suffix = [b, c] ;
Suffix = [c] ;
Suffix = [] ;
false.
这里的_
可以代表列表[]
、[a]
、[a, b]
、[a, b, c]
中的任意一个。但我不需要告诉你这个。如果您给匿名变量 _
一个合适的名称,Prolog 可以告诉您:
?- append(Prefix, Suffix, [a, b, c]).
Prefix = [],
Suffix = [a, b, c] ;
Prefix = [a],
Suffix = [b, c] ;
Prefix = [a, b],
Suffix = [c] ;
Prefix = [a, b, c],
Suffix = [] ;
false.
相比之下,术语[_]
不代表任意列表。它代表一个绝对只有一个元素的列表。该元素(表示为 _
)是任意的。
例如:
?- append([_], Suffix, [a, b, c]).
Suffix = [b, c].
或者,再次使用适当的变量名,以便我们可以看到绑定:
?- append([X], Suffix, [a, b, c]).
X = a,
Suffix = [b, c].
这就是说问题的定义:
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
接近正确。但是 _
的两种用法都不会“删除”一个元素。他们每个“删除”任意数量的元素。所以你不只是得到列表的中间:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [] ;
Middle = [a] ;
Middle = [a, b] ;
Middle = [a, b, c] ;
Middle = [a, b, c, d] ;
Middle = [a, b, c, d, e] ;
Middle = [] ;
Middle = [b] ;
Middle = [b, c] ;
Middle = [b, c, d] ;
Middle = [b, c, d, e] ;
Middle = [] ;
Middle = [c] ;
Middle = [c, d] ;
Middle = [c, d, e] ;
Middle = [] ;
Middle = [d] ;
Middle = [d, e] ;
Middle = [] ;
Middle = [e] ;
Middle = [] ;
false.
如果我们想从前面和后面“删除”恰好一个元素的列表,我们必须写 [_]
:
listWithinList(X, Y) :-
append([_], Y2, Y),
append(X, [_], Y2).
现在的行为如下:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [b, c, d] ;
false.
此外,请注意 [_]
和 [_|_]
之间的区别。前者代表 exactly 一个元素的列表。后者代表 一个或多个 元素的列表。在这种情况下,您不想“删除”多个元素,因此使用 [_|_]
,就像其他答案之一所暗示的那样,绝对是胡说八道。
最后,Prolog 可以向我们建议进一步简化:
?- append([X], Xs, Ys).
Ys = [X|Xs].
附加一个单元素列表 [X]
和一个任意列表 Xs
给出一个列表,我们也可以在不使用 append
的情况下将其写为 [X | Xs]
。因此不需要 append
调用之一。我可能会这样写这个谓词:
list_middle(List, Middle) :-
append([_First | Middle], [_Last], List).
并像这样使用它:
?- list_middle([a, b, c, d, e], Middle).
Middle = [b, c, d] ;
false.
或者像这样:
?- list_middle(List, [1, 2, 3]).
List = [_2658, 1, 2, 3, _2664].
对于此类任务,语法非常直观。简单描述一下我们有什么:
list_within(Xs, Ys) :-
phrase(( [_First], seq(Ys), [_Last] ), Xs).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
即首先是元素_First
,然后是序列Ys
,最后是元素_Last
。