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

时间:2017-04-14 15:50:10

标签: list prolog member

我想查找列表列表中是否存在给定元素。如果元素存在于某处是第一个列表列表,我只会变为真。

有什么建议吗?

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

7 个答案:

答案 0 :(得分:9)

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

member/2类似,这会产生许多冗余答案,例如:

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

或者,您可能希望使用memberd/2代替member/2

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

?- memberlists2(X, [[a,a],[a],[a]]).
   X = a
;  X = a   % redundant
;  false.

这样做要好得多,但仍然无法删除所有多余的答案。

对于删除所有此类冗余的解决方案,已设置了赏金。

答案 1 :(得分:7)

这个怎么样?

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).

答案 2 :(得分:7)

这是@ user27815(s(0)两种解决方案)非常好的第二种解决方案的更紧凑版本。实际上不需要像在member_lists_t / 3中那样在谓词member_lists / 2中使用reification。实际上,在找到第一个解决方案后,使用memberd_t/3作为if_/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

确定性地终止。

答案 3 :(得分:6)

使用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).

答案 4 :(得分:5)

问题是[[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程序来说很常见(可能是口译员警告T1T2只提到过一次。)

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

你的谓词做了很多“打包”和“解包”。此外,我们可以使用member/2内置。所以我们可以重写它:

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

答案 5 :(得分:3)

以下是使用sort/2flat/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...)

答案 6 :(得分:-3)

原始问题的答案如下:

memberlist(X, [X| _]) :- !.
memberlist(X, [[A|B]|_]) :-
    memberlist(X,[A|B]), !.
memberlist(X, [_ | Rest]) :-
    memberlist(X, Rest).

此解决方案仅在查询中给出X值时才会给出一个结果。通过更多的工作,可以将其更改为尾递归算法。但问题似乎扩展到寻找一种方法来让它返回作为所有嵌入列表成员的单例元素集。

解决方案是将列表展平为单个列表,然后将列表转换为集合。

来自cs.uni-potsdam.de的flatten代码是:

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).

将列表设置为设置的代码(来自http://www.cs.oswego.edu/~odendahl/coursework/notes/prolog/synopsis/

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

make_set([],[]).
make_set(X,Y) :- setof(Z,member(Z,X),Y).

所以最后一块是:

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

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

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