查找数字是否是列表中元素的成员

时间:2017-05-06 13:20:30

标签: prolog

我正在尝试创建一个谓词,它返回包含我给出的某个数字的列表元素。

示例:

?- where_is_it( [ [1,2,3] , [1,2,7] , [4,5] , [8] ] , 7 , X ).

X=[1,2,7].

我是一个相对较新的prolog程序员,所以这是我的代码:

where_is_it([],_,[]). 
where_is_it([H|T],Num,H):-
    member([Num],H),!,
    where_is_it(T,Num,[]).

非常感谢

7 个答案:

答案 0 :(得分:6)

where_is_it(Xss, X, Xs) :-
   member(Xs, Xss),
   member(X, Xs).

答案 1 :(得分:6)

您可以使用模块reif中的if_/3memberd_t/2,以便更具确定性:

where_is_it([H|T], X, L) :-
  if_(memberd_t(X,H), L=H, where_is_it(T, X, L)).

答案 2 :(得分:5)

以下是使用tmember/2的实现:

where_is_it(InList, X, L):- tmember(check(X,L),InList).

check(X,L,L1,T):- if_( memberd_t(X,L1), (T = true, L = L1), T = false).

答案 3 :(得分:4)

这是仅使用tmember/2(=)/3而没有任何显式递归的版本:

where_is_it(Xss,X,Xs) :-
   tmember(=(Xs),Xss),
   tmember(=(X),Xs).

OP给出的查询按预期工作:

   ?- where_is_it([[1,2,3],[1,2,7],[4,5],[8]],7,X).
X = [1,2,7] ? ;
no

此版本的部分功能:如果元素出现在多个列表中(与if_/3memberd_t的版本不同):

   ?- where_is_it([[1,2,3],[1,2,7],[4,5],[8]],1,X).
X = [1,2,3] ? ;
X = [1,2,7] ? ;
no

一个列表中多次出现的元素只匹配一次(与带有成员/ 2的版本不同):

   ?- where_is_it([[1,2,3,1],[4,5],[8]],1,X).
X = [1,2,3,1] ? ;
no

同一个列表的多次出现只匹配一次(与带有member / 2的版本不同):

   ?- where_is_it([[1,2,3],[1,2,3],[4,5],[8]],1,X).
X = [1,2,3] ? ;
no

即使有一个打开的列表(与包含成员/ 2的版本以及包含if_/3memberd_t的版本不同):

   ?- where_is_it([[1,2,3],[1,2,7],[4,5],[8],[1|_]],1,X).
X = [1,2,3] ? ;
X = [1,2,7] ? ;
X = [1|_A],
dif([1|_A],[1,2,3]),
dif([1|_A],[1,2,7]) ? ;
no

如果实际元素是可变的:

   ?- where_is_it([[1,2,3],[8]],Y,X).
X = [1,2,3],
Y = 1 ? ;
X = [1,2,3],
Y = 2 ? ;
X = [1,2,3],
Y = 3 ? ;
X = [8],
Y = 8 ? ;
no

最常见的查询(与包含member / 2的版本(仅略有)以及与if_/3memberd_t的版本不同):

   ?- where_is_it(Xss,X,Xs).
Xs = [X|_A],
Xss = [[X|_A]|_B] ? ;
Xs = [_A,X|_B],
Xss = [[_A,X|_B]|_C],
dif(X,_A) ? ;
Xs = [_A,_B,X|_C],
Xss = [[_A,_B,X|_C]|_D],
dif(X,_B),
dif(X,_A) ? ;
...

有一些限制(与成员/ 2的版本(仅略有)以及带有if_/3memberd_t的版本不同):

   ?- Xss=[_,_],Xs=[_,_],where_is_it(Xss,X,Xs).
Xs = [X,_A],
Xss = [[X,_A],_B] ? ;
Xs = [_A,X],
Xss = [[_A,X],_B],
dif(X,_A) ? ;
Xs = [X,_A],
Xss = [_B,[X,_A]],
dif([X,_A],_B) ? ;
Xs = [_A,X],
Xss = [_B,[_A,X]],
dif(X,_A) ? ;
no

答案 4 :(得分:3)

您应该阅读您的条款所说的内容吗?你可能需要一个句子,“如果X是H的成员,那么H就是解决方案”:

where_is_it([H|_], X, H) :-
    member(X, H).

然后你仍然需要另一个条款,说明你可能在列表的其余部分有一个解决方案:

where_is_it([_|T], X, H) :-
    where_is_it(T, X, H).

也许这足以开始?

答案 5 :(得分:2)

好的,让我们来看看你的代码。第一个条款很好,无论我们在寻找什么,它都不在空列表中。

where_is_it([],_,[]).

这是你的第二个条款:

where_is_it([H|T],Num,H):-
    member([Num],H),!,
    where_is_it(T,Num,[]).

这里有几个问题:

首先,代替member([Num],H)您可能需要member(Num,H)表示Num是列表H的元素。

其次,如果这是Num是H成员的情况的条款,则递归应该如下:

 where_is_it([H|T],Num,[H|Found]):-
     member(Num,H),!,
     where_is_it(T,Num,Found).

此子句现在表示,只要Num是H的成员,H就属于我们的解决方案列表,我们必须在列表的尾部(即T中)寻找更多解决方案并在Found中收集它们。

对于Num不是H的成员的情况,您需要一个附加条款:

 where_is_it([H|T],Num,Found):-
     where_is_it(T,Num,Found).

此子句不会更改找到的解决方案列表。

因此完整的代码是:

where_is_it([],_,[]).

where_is_it([H|T],Num,[H|Found]):-
     member(Num,H),!,
     where_is_it(T,Num,Found).

 where_is_it([_H|T],Num,Found):-
     where_is_it(T,Num,Found).

答案 6 :(得分:0)

我没有看到reif的任何优势,除了减速:-(,采取这些解决方案:

传统解决方案:

/* variant 1 */
where_is_it(Xss, X, Xs) :-
   member(Xs, Xss),
   member(X, Xs).

/* variant 2 */
where_is_it2(Xss, X, Xs) :-
   member(Xs, Xss),
   memberchk(X, Xs), !.

/* variant 3 */
where_is_it3([H|T], X, R) :-
   (memberchk(X, H) -> R=H; where_is_it3(T, X, R)).

reif解决方案:

/* variant 1 */
where_is_it(Xss, X, Xs) :-
   tmember(=(Xs), Xss),
   tmember(=(X), Xs).

/* variant 2 */
where_is_it2(InList, X, L):- 
   tmember(check(X,L),InList).
check(X,L,L1,T):- 
   if_( memberd_t(X,L1), (T = true, L = L1), T = false).

/* variant 3 */
where_is_it3([H|T], X, L) :-
   if_(memberd_t(X,H), L=H, where_is_it3(T, X, L)).

时间安排如下:

传统解决方案:

/* variant 1 */
?- where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3] ;
X = [1, 2, 7] ;
false.

/* variant 2 */
?- where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].

/* variant 3 */
?- where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].

/* variant 1 */
?- time((between(1,1_000_000,_), 
         where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 20,000,001 inferences, 1.031 CPU in 1.031 seconds (100% CPU, 19393940 Lips)
true.

/* variant 2 */
?- time((between(1,1_000_000,_), 
         where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 7,000,000 inferences, 0.422 CPU in 0.422 seconds (100% CPU, 16592593 Lips)
true.

/* variant 3 */
time((between(1,1_000_000,_), 
         where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 6,000,000 inferences, 0.297 CPU in 0.297 seconds (100% CPU, 20210526 Lips)
true.

reif解决方案:

/* variant 1 */
?- where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3] ;
X = [1, 2, 7] ;
false.

/* variant 2 */
?- where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].

/* variant 3 */
?- where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].

/* variant 1 */
?- time((between(1,1_000_000,_), 
         where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 400,000,001 inferences, 18.688 CPU in 18.674 seconds (100% CPU, 21404682 Lips)
true.

/* variant 2 */
?- time((between(1,1_000_000,_), 
         where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 18,000,000 inferences, 1.203 CPU in 1.203 seconds (100% CPU, 14961039 Lips)
true.

/* variant 3 */
?- time((between(1,1_000_000,_), 
         where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,_), 
         fail; true)).
% 13,000,000 inferences, 0.688 CPU in 0.687 seconds (100% CPU, 18909091 Lips)
true.

基本上,reif解决方案是ca. 18次,约相应的3倍慢2倍。