在Prolog中搜索(相同)两个元素的列表

时间:2014-08-24 00:50:18

标签: list prolog prolog-dif

如何在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

5 个答案:

答案 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 简单!使用 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/2once/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中使用。

:)