Существует ли элемент в списке списков?
Я хочу найти, существует ли данный элемент в списке списков. Я только верю, если элемент существует где-то, это первый список списков.
Любые советы?
memberlist(X,[[X|T1]|T2]).
memberlist(X,[[H|T1]|T2]) :-
memberlist(X,[T1|T2]).
Ответы
Ответ 1
Проблема в том, что [[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
упоминались только один раз).
Поэтому, если первый список исчерпан, мы просто переходим к следующему списку.
Ваш предикат делает много "упаковки" и "распаковки". Кроме того, мы можем использовать встроенный member/2
. Поэтому мы можем переписать его:
memberlist(X,[H|_]) :-
member(X,H).
memberlist(X,[_|T2]) :-
memberlist(X,T2).
Ответ 2
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.
Это намного лучше, но все же не удаляет все избыточные ответы.
Для решения, которое удаляет все такие избыточности, была установлена баунти.
Ответ 3
Как насчет этого?
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).
Ответ 4
Вот более компактная версия очень приятного второго решения от пользователя @user27815 (s (0) для обоих решений). На самом деле нет необходимости использовать reification в предикате member_lists/2, как это делается в member_lists_t/3. Фактически использование 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
заканчивается детерминистически.
Ответ 5
С 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).
Ответ 6
Вот мой подход с использованием 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).
Testcases:
?- 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...)
Ответ 7
Ответ на исходный вопрос выглядит следующим образом:
memberlist(X, [X| _]) :- !.
memberlist(X, [[A|B]|_]) :-
memberlist(X,[A|B]), !.
memberlist(X, [_ | Rest]) :-
memberlist(X, Rest).
Это решение даст только один результат, когда X задано значение в запросе. С небольшим количеством работы это можно изменить на хвостовой рекурсивный алгоритм. Но вопрос, похоже, расширился, чтобы найти способ вернуть это множество элементов singleton, которые являются членами всех встроенных списков.
Решение состоит в том, чтобы сгладить списки в один список и затем перевести список в набор.
Код для сглаживания из 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).
Код для поворота списка для установки (из 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).
Конечно, это не совсем удовлетворительно, потому что оно не является хвостом рекурсивным и не очень эффективным. Но придумывание эффективного хвостового рекурсивного решения займет у меня пару часов, и я должен косить газон.