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

Jay*_*Jay 11 prolog

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

例:

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

X=[1,2,7].
Run Code Online (Sandbox Code Playgroud)

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

where_is_it([],_,[]). 
where_is_it([H|T],Num,H):-
    member([Num],H),!,
    where_is_it(T,Num,[]).
Run Code Online (Sandbox Code Playgroud)

非常感谢你

fal*_*lse 6

where_is_it(Xss, X, Xs) :-
   member(Xs, Xss),
   member(X, Xs).
Run Code Online (Sandbox Code Playgroud)

  • @ j4n bur53,是否有任何特别的原因可以低估所有帖子,还有很多其他帖子?你发现了什么错误或无益吗?这样的行为无助于堆栈溢出......即使你不喜欢某些东西,你也可以先发表评论来改进它...... (5认同)
  • 缺点:"X"的许多冗余解决方案.[这](http://stackoverflow.com/a/43821691/772868)和[那](http://stackoverflow.com/a/43876945/772868)完全避免这种情况. (4认同)

cod*_*der 6

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

where_is_it([H|T], X, L) :-
  if_(memberd_t(X,H), L=H, where_is_it(T, X, L)).
Run Code Online (Sandbox Code Playgroud)


tas*_*tas 5

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

where_is_it(Xss,X,Xs) :-
   tmember(=(Xs),Xss),
   tmember(=(X),Xs).
Run Code Online (Sandbox Code Playgroud)

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

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

该版本的一些功能: 如果该元素出现在多个列表中(与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
Run Code Online (Sandbox Code Playgroud)

一个列表中多次出现的元素仅匹配一次(与 member/2 的版本不同):

   ?- where_is_it([[1,2,3,1],[4,5],[8]],1,X).
X = [1,2,3,1] ? ;
no
Run Code Online (Sandbox Code Playgroud)

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

   ?- where_is_it([[1,2,3],[1,2,3],[4,5],[8]],1,X).
X = [1,2,3] ? ;
no
Run Code Online (Sandbox Code Playgroud)

即使使用开放列表(与 member/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
Run Code Online (Sandbox Code Playgroud)

如果实际元素是可变的:

   ?- 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
Run Code Online (Sandbox Code Playgroud)

最通用的查询(与 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) ? ;
...
Run Code Online (Sandbox Code Playgroud)

有一些约束(与 member/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
Run Code Online (Sandbox Code Playgroud)

  • `tmember(=(X),Xs)` 归结为 `memberd(X, Xs)`。实际上,我打算像 [@coders](http://stackoverflow.com/a/43821691/772868) 那样进行一些范围界定。无论如何,s(X)。 (3认同)

cod*_*der 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).
Run Code Online (Sandbox Code Playgroud)

  • @ j4n bur53,因为它留下了选择点,而且答案是正确的事实并不排除其他答案!! (4认同)
  • @ j4n bur53,即使问题中最简单的查询留下选择点你在哪里看不到非确定性!! (4认同)
  • @ j4n bur53,看到最后的评论!! (4认同)
  • @ j4n bur53,您对数学证明的期望是什么?你能证明它不是更有效吗?正如我所说,你可以很容易地看到`where_is_it([[1,2,3],[1,2,7],[4,5],[8]],7,X).`留下选择点答案不!! (4认同)
  • 你提到的明确的解决方案并不是那么有效...为了更有效率而给予reif答案的赏金,所有这些答案都是互补的并且不包含任何错误......只有一些其他的解决方案问题!! (3认同)
  • @ j4n bur53,这不是来自OP,也不是假的,所以我不会提供它,但正如我说的只是测试上面的查询我的解决方案是确定性的,而另一个不是!我并不认为它是完美的,但在大多数情况下并没有留下选择点. (3认同)
  • 说`listing(where_is_it3)`.它不应该包含`call/2`-goals. (2认同)
  • 更加系统的比较,如/sf/answers/2569104121/会有所帮助 (2认同)

小智 2

您也许应该阅读您的条款内容?您可能需要一个子句,其中表示“如果 X 是 H 的成员,则 H 是解决方案”:

where_is_it([H|_], X, H) :-
    member(X, H).
Run Code Online (Sandbox Code Playgroud)

然后你还需要另一个子句来说明也许你在列表的其余部分有一个解决方案:

where_is_it([_|T], X, H) :-
    where_is_it(T, X, H).
Run Code Online (Sandbox Code Playgroud)

也许这对于开始就足够了?