List 列表列表中是否存在元素?

List 列表列表中是否存在元素?,list,prolog,member,List,Prolog,Member,我想知道列表列表中是否存在给定的元素。只有当元素存在于列表的第一个列表的某个地方时,我才得到正确答案 有什么建议吗 memberlist(X,[[X|T1]|T2]). memberlist(X,[[H|T1]|T2]) :- memberlist(X,[T1|T2]). 问题在于,[[H|T1]| T2]只匹配第一个列表中至少有一个元素的情况。事实上:[[]、[1,4]、[2,5]]并不与[[H | T1]| T2]统一 因此,您可以通过添加一个子句来解决此问题: memberlist(

我想知道列表列表中是否存在给定的元素。只有当元素存在于列表的第一个列表的某个地方时,我才得到正确答案

有什么建议吗

memberlist(X,[[X|T1]|T2]).
memberlist(X,[[H|T1]|T2]) :-
  memberlist(X,[T1|T2]).

问题在于,
[[H|T1]| T2]
只匹配第一个列表中至少有一个元素的情况。事实上:
[[]、[1,4]、[2,5]]
并不与
[[H | T1]| T2]
统一

因此,您可以通过添加一个子句来解决此问题:

memberlist(X,[[]|T2]) :-
    memberlist(X,T2).
因此,我们得到:

memberlist(X,[[X|_]|_]).
memberlist(X,[[H|T1]|T2]) :-
    memberlist(X,[T1|T2]).
memberlist(X,[[]|T2]) :-
    memberlist(X,T2).
第一个子句还使用下划线指定我们对这些变量“不感兴趣”。这在Prolog程序中很常见(可能解释器警告说,
T1
T2
只提到过一次)

因此,如果第一个列表已用尽,我们只需移动到下一个列表

您的谓词执行大量的“打包”和“解包”。此外,我们还可以使用
成员/2
内置。所以我们可以重写它:

memberlist(X,[H|_]) :-
    member(X,H).
memberlist(X,[_|T2]) :-
  memberlist(X,T2).
member/2
类似,这会产生许多冗余的答案,如:

?- memberlists(X, [[a,a],[a],[a]]).
   X = a
;  X = a  % redundant
;  X = a  % redundant
;  X = a. % redundant
或者,您可能希望使用代替
member/2

memberlists2(X, Xss) :-
   memberd(Xs, Xss),
   memberd(X, Xs).

?- memberlists2(X, [[a,a],[a],[a]]).
   X = a
;  X = a   % redundant
;  false.
这要好得多,但仍然不能消除所有多余的答案


对于消除所有此类冗余的解决方案,已经设置了一个悬赏。

以下是我使用
sort/2
flat/2
的方法,该方法仅将列表展平一级:

memberlists(X, Xss) :- Xss = [_|_], 
                       flat(Xss, FL), 
                       sort(FL, OutL), 
                       memberd(X, OutL).

memberd(X, [X|_Xs]).
memberd(X, [Y|Xs]) :-
   dif(X,Y),
   memberd(X, Xs).                       

flat([],[]).
flat([H|T],R) :- H = [_|_], flat(T,T1), append(H,T1,R).
测试用例:

 ?- memberlists(X,[[a,A]]), A = a.
X = A, A = a ;
false.

?- memberlists(X,[[a]|Xs]), Xs = [_|_].
Xs = [[X]] ;
X = a,
Xs = [[_G13004]],
dif(a, _G13004) ;
Xs = [[X, _G12784]] .

?- memberlists(X,[[a,a],[Y],[b]]).
X = Y ;
X = a,
dif(a, Y) ;
X = b,
dif(b, Y) ;
false.

?- memberlists(X,[[a,a],[a],[a]]).
X = a ;
false.

?- memberlists(X,[[[a,a],[a],[a]]]).
X = [a] ;
X = [a, a] ;
false.

?- memberlists(X,[L]).
L = [X] ;
L = [X, _G12710] ;
L = [_G12923, X],
dif(X, _G12923) ;
L = [X, _G12710, _G12716] ;
L = [_G12935, X, _G12941],
dif(X, _G12935) . (and goes on...)

?- memberlists(X,L).
L = [[X]]
L = [[X, _G12704]] ;
L = [[_G12920, X]],
dif(X, _G12920) ;
L = [[X, _G12704, _G12710]] ;
L = [[_G12932, X, _G12938]],
dif(X, _G12932) ;
L = [[_G13018, _G13021, X]],
dif(X, _G13021),
dif(X, _G13018) ;
L = [[X, _G12704, _G12710, _G12716]] . (and goes on...)
这个怎么样

list([])     --> [].
list([L|Ls]) --> [L], list(Ls).

concatenation([]) --> [].
concatenation([List|Lists]) -->
   list(List),
   concatenation(Lists).

memberd(X, [X|_Xs]).
memberd(X, [Y|Xs]) :-
   dif(X,Y),
   memberd(X, Xs).

memberlists(X, Lists):-
   phrase(concatenation(Lists),List),
   memberd(X,List).
使用if/3:

memberd_t(_,[],false).
memberd_t(X,[Y|Ys],Truth) :-
 if_(X=Y, Truth=true, memberd_t(X,Ys,Truth)).

member_lists_t(_,[],false).
member_lists_t(X,[H|T],Truth):-
 if_(memberd_t(X,H),Truth=true,member_lists_t(X,T,Truth)).

member_lists(X,Lists):-
 member_lists_t(X,Lists,true).

下面是@user27815(两个解决方案的s(0))编写的非常好的第二个解决方案的更紧凑版本。实际上,在谓词成员列表/2中不需要像在成员列表/3中那样使用物化。事实上,在找到第一个解后,使用作为的第一个参数就足以终止。因此,这种关系可以表示为一个单一的规则和一个单一的目标,如下所示:

member_lists(X,[H|T]) :-
  if_(memberd_t(X,H),true,member_lists(X,T)).
询问

   ?- member_lists(X,[[a,a],[a]]).
X = a ? ;
no
   ?- member_lists(X,[[X|_]|_]).

true
只产生一个单一的解决方案。询问

   ?- member_lists(X,[[X|_]|_]).

true

是决定性终止。

原始问题的答案如下:

memberlist(X, [X| _]) :- !.
memberlist(X, [[A|B]|_]) :-
    memberlist(X,[A|B]), !.
memberlist(X, [_ | Rest]) :-
    memberlist(X, Rest).
当X在查询中被赋予一个值时,此解决方案将只给出一个结果。再多做一点工作,就可以将其更改为尾部递归算法。但问题似乎扩展到寻找一种方法,让它返回所有嵌入列表的成员的单例元素集

解决方案是将列表展平为单个列表,然后将列表转换为一组

cs.uni-potsdam.de中的展平代码为:

flatten(List, Flat) :-
    flatten(List, Flat, []).

flatten([], Res, Res) :- !.
flatten([Head|Tail], Res, Cont) :-
        !,
        flatten(Head, Res, Cont1),
        flatten(Tail, Cont1, Cont).
flatten(Term, [Term|Cont], Cont).
将列表转到设置(从)的代码

因此,最后一点是:

setofmembers(NestedLists, Set) :-
    flatten(NestedLists,Flat),
    make_set(Flat,Set).

memberlist2(X,Lists) :-
    setofmembers(Lists,Set),
    member(X,Set).


当然,这并不完全令人满意,因为它不是尾部递归的,也不是非常有效。但是想出一个高效的尾部递归解决方案需要花费我几个小时的时间,而且我必须修剪草坪。

有点错过了。问候:)还是一样complex@false你能提供一些不那么复杂的东西吗?@Alator:请看我的答案
member(Xs,Xss),member(X,Xs)
对于
memberlist(X,[[a]| Xs]),Xs不正确地失败.
它应该成功(或循环)。为
成员列表(X,[[a,a]])、a=a生成了两个答案。
因此仍然存在冗余解决方案。@false,使用memberd/2解决问题请查看更新的答案,任何建议都可以接受
memberlist(X,[[X | | | | | | | |)]。
可以决定性地成功,这是一个纯粹的、好的解决方案。但真的有必要先转换整个列表吗?这不是一个明确的要求。(如果你想提交另一个解决方案,不要修改你的答案,而是使用一个单独的答案!)在这种情况下,你的解决方案不会终止,但你甚至可以预期它会决定性地成功:
成员列表(X,[[X | | | | |])
。将其与同样成功和终止的
memberd(X[X |)
进行比较。你是说
memberd(t/3)
代替
memberd/3
,对于
成员列表(t/3)
。我想应该是memberd(t)t),但仍然是成员列表??正如在if_u/3中所调用的那样,在
成员列表/2
中不需要具体化!显然,这是最好的解决办法。然而,看起来如此简单,却如此低效,这不是有点奇怪吗?也许这应该进入一个更进一步的问题&赏金。@false:是的,这确实很奇怪。理查德·奥基夫(Richard O'Keefe)在《序言的技巧》的导论章节中写道,这本书的主题之一是“优雅不是随意的”。我发现这是一个非常准确的观察结果。但这似乎是一个反例。至少根据他对声明的第一次解释(效率)。然而,在可维护性(第二种解释)方面,它仍然适用:在你的帖子中,我可以第一眼看到发生了什么。在我的。。。好吧,如果我不熟悉物化…至少你的解决方案真的是纯粹而有效的!也许更高的顺序可能涵盖了抽象……如果
L
是一个列表,
X
L
的一个元素的成员,那么谓词
memberlist(X,L)
应该是正确的。因此,
memberlist(X[a])。
应该失败,但您的实现不会失败。顺便说一句,
a
可能被视为未指定,但它也适用于
memberlist(X,[[])。
:空列表的列表不包含任何内容,但实现声称空列表包含空列表。
setofmembers(NestedLists, Set) :-
    flatten(NestedLists,Flat),
    make_set(Flat,Set).

memberlist2(X,Lists) :-
    setofmembers(Lists,Set),
    member(X,Set).