如何在Prolog中搜索出现多次的特定元素?
例如,如果我们在列表[1,2,3,4,1]
中搜索元素1
,则Prolog应返回true
,否则false
将返回所有其他数字。
这是我到目前为止所做的:
duplicate([], _) :-
false,
!.
duplicate([X|_], X) :-
true,
!.
duplicate([H|T], X) :-
T = [_|T1],
duplicate(T, X),
duplicate(T1, X).
我的基本想法是搜索列表,直到找到我要查找的元素,然后再次搜索列表的尾部。我不想使用Prolog提供的member()函数。
如果查询询问,Prolog还应该返回多次出现的元素:duplicate([1,2,3,4,1], X)
,应该打印X = 1
。
答案 0 :(得分:3)
我在评论中说的是:我想要列表中的两个项目不在同一个地方所以
duplicate(L, V) :-
% nth0 gives the index (from 0) of an element in a list
% element V is at the place Id1 in L
nth0(Id1, L, V),
% element V is at the place Id2 in L
nth0(Id2, L, V),
% Id1 is different from Id2
% It is more usefull to say that Id1 < Id2
% Thanks **false** for the improvement
Id1 < Id2.
另一种方法是说:我删除列表中的元素(这是通过select / 3在SWI-Prolog中完成的),然后检查它是否在列表的其余部分中:
duplicate(L, V) :-
select(V, L, L1),
member(V, L1).
答案 1 :(得分:3)
这里是使用语法的明显版本。从某种意义上说,我们正在描述包含重复的列表的结构。该结构如下:
...
),[V]
),...
)[V]
)duplicate(L, V) :-
phrase(( ..., [V], ..., [V], ... ), L).
... --> [] | [_], ... .
作为缺点,此版本将为
等查询生成冗余答案?- duplicate([a,a,a],a).
使用dif/2
:
duplicate(L, V) :-
phrase(( all(dif(V)), [V], all(dif(V)), [V], ... ), L).
非终端all//1
的定义。
答案 2 :(得分:3)
Pure 简单!使用meta-predicate tcount/3
与明确的术语相等(=)/3
,如下所示:
?- tcount(=(X), [1,2,3,4,1], 2).
X = 1 ; % succeeds, but leaves choicepoint
false.
?- tcount(=(1), [1,2,3,4,1], 2).
true. % succeeds deterministically
?- tcount(=(X), [b,c,d,a,b,a,c], 2).
X = b ;
X = c ;
X = a ;
false.
?- tcount(=(a), [b,c,d,a,b,a,c], 2).
true. % succeeds deterministically
最后,让我们运行以下非常一般的查询:
?- tcount(=(a), Ls, 2).
Ls = [a,a] ;
Ls = [a,a,_X], dif(_X,a) ;
Ls = [a,a,_X,_Y], dif(_X,a), dif(_Y,a) ;
Ls = [a,a,_X,_Y,_Z], dif(_X,a), dif(_Y,a), dif(_Z,a) ...
答案 3 :(得分:2)
@false的解决方案尽可能干净。这是一个更详细的解决方案,用更简单的术语来陈述问题。要记住的一件事是,“重复”元素可能意味着一个元素恰好出现两次 - 这就是这个谓词解释它的方式 - 或者它可能意味着一个元素出现不止一次 - 这就是你可能的意思(所以名称duplicate
实际上是误导性的)
%% duplicate(List, Element) is true for every matching pair of _Element_ in _List_
duplicate([First|Rest], Element) :-
duplicate_1(Rest, First, Element).
% First occurrence
duplicate_1([This|Rest], X, X) :- % first occurrence
duplicate_2(Rest, This, X).
duplicate_1([This|Rest], _, X) :- % look further for first occurrence
duplicate_1(Rest, This, X).
% Second occurrence
duplicate_2(_, X, X). % second occurrence
duplicate_2([This|Rest], _, X) :- % look further for second occurrence
duplicate_2(Rest, This, X).
现在可以在所有方向使用:
?- duplicate([b,c,d,a,b,a,c], X).
X = b ;
X = c ;
X = a ;
false.
?- duplicate([b,c,d,a,b,a,c], a).
true ;
false.
?- duplicate(L, a).
L = [a, a|_G274] ;
L = [a, _G273, a|_G277] ;
L = [a, _G273, _G276, a|_G280] .
如果出现问题,您必须使用剪切或dif/2
或once/1
来删除多个答案。具体取决于您希望如何使用谓词。
答案 4 :(得分:0)
对于问题的第一部分,我找到了一个简单的解决方案:
duplicated([H|T], Item) :- H == Item, second_stage(T, Item). %first occurence found
duplicated([H|T], Item) :- duplicated(T, Item).
second_stage([H|T], Item) :- H == Item. %second occurence found -> match!
second_stage([H|T], Item) :- second_stage(T, Item).
这将给出真实的f.e.有重复的([1,2,3,1,5],1)。
对于第二部分(使用Variable查询)我会尝试找到一种方法......但我不这样做 知道这是否可以在Prolog中使用。
:)