问题
I need to find the combinations in a list of lists. For example, give the following list,
List = [[1, 2], [1, 2, 3]]
These should be the output,
Comb = [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3]]
Another example:
List = [[1,2],[1,2],[1,2,3]]
Comb = [[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3]....etc]
I know how to do it for a list with two sublists but it needs to work for any number of sublists.
I'm new to Prolog, please help.
回答1:
This answer hunts the bounty offered "for a pure solution that also takes into account for Ess".
Here we generalize this previous
answer like so:
list_crossproduct(Xs, []) :-
member([], Xs).
list_crossproduct(Xs, Ess) :-
Ess = [E0|_],
same_length(E0, Xs),
maplist(maybelonger_than(Ess), Xs),
list_comb(Xs, Ess).
maybelonger_than(Xs, Ys) :-
maybeshorter_than(Ys, Xs).
maybeshorter_than([], _).
maybeshorter_than([_|Xs], [_|Ys]) :-
maybeshorter_than(Xs, Ys).
list_crossproduct/2 gets bidirectional by relating Xs and Ess early.
?- list_comb(Xs, [[1,2,3],[1,2,4],[1,2,5]]). nontermination % BAD! ?- list_crossproduct(Xs, [[1,2,3],[1,2,4],[1,2,5]]). Xs = [[1],[2],[3,4,5]] % this now works, too ; false.
Sample query having multiple answers:
?- list_crossproduct(Xs, [[1,2,3],[1,2,4],[1,2,5],X,Y,Z]).
X = [1,2,_A],
Y = [1,2,_B],
Z = [1,2,_C], Xs = [[1],[2],[3,4,5,_A,_B,_C]]
; X = [1,_A,3],
Y = [1,_A,4],
Z = [1,_A,5], Xs = [[1],[2,_A],[3,4,5]]
; X = [_A,2,3],
Y = [_A,2,4],
Z = [_A,2,5], Xs = [[1,_A],[2],[3,4,5]]
; false.
回答2:
For completeness, here is the augmented version of my comment-version. Note nilmemberd_t/2 which is inspired by memberd_t/2.
nilmemberd_t([], false).
nilmemberd_t([X|Xs], T) :-
if_(nil_t(X), T = true, nilmemberd_t(Xs, T)).
nil_t([], true).
nil_t([_|_], false).
list_comb(List, []) :-
nilmemberd_t(List, true).
list_comb(List, Ess) :-
bagof(Es, maplist(member,Es,List), Ess).
Above version shows that "only" the first clause was missing in my comment response. Maybe even shorter with:
nilmemberd([[]|_]).
nilmemberd([[_|_]|Nils]) :-
nilmemberd(Nils).
This should work for Prologs without constraints. With constraints, bagof/3 would have to be reconsidered since copying constraints is an ill-defined terrain.
回答3:
Here's a way to do it using maplist/3 and append/2:
list_comb([], [[]]). list_comb([Xs|Xss], Ess) :- Xs = [_|_], list_comb(Xss, Ess0), maplist(aux_x_comb(Ess0), Xs, Esss1), append(Esss1, Ess). aux_x_comb(Ess0, X, Ess1) :- maplist(head_tail_list(X), Ess0, Ess1). head_tail_list(X, Xs, [X|Xs]).
Sample query:
?- list_comb([[a,b],[f,g],[x,y,z]], Ess).
Ess = [[a,f,x],[a,f,y],[a,f,z],
[a,g,x],[a,g,y],[a,g,z],
[b,f,x],[b,f,y],[b,f,z],
[b,g,x],[b,g,y],[b,g,z]].
Here's how it works! As an example, consider these goals:
list_comb([[a,b],[f,g],[x,y,z]], Ess)list_comb([ [f,g],[x,y,z]], Ess0)
How can we get from Ess0 to Ess?
We look at the answers to the latter query:
?- list_comb([[f,g],[x,y,z]], Ess0). Ess0 = [[f,x],[f,y],[f,z], [g,x],[g,y],[g,z]].
... place
abefore[f,x], ...,[g,z]...?- maplist(head_tail_list(a), [[f,x],[f,y],[f,z], [g,x],[g,y],[g,z]], X). X = [[a,f,x],[a,f,y],[a,f,z], [a,g,x],[a,g,y],[a,g,z]].... then do the same for
b.maplist(aux_x_comb)helps us handle all items:?- maplist(aux_x_comb([[f,x],[f,y],[f,z], [g,x],[g,y],[g,z]]), [a,b], X). X = [[[a,f,x],[a,f,y],[a,f,z], [a,g,x],[a,g,y],[a,g,z]], [[b,f,x],[b,f,y],[b,f,z], [b,g,x],[b,g,y],[b,g,z]]].To get from a list of lists to a list use
append/2.
I hope this explanation was more eludicating than confusing:)
回答4:
Sorry for having to do a total erase on the existing input. You can use the history to go back and see what was deleted. In adding the last part went way past the 30,000 character limit and decided to start over.
This is the answer done like a mechanical counter
base_extend(R,[],[R]) :- !.
base_extend([],[Extender|Extenders],[H|T]) :-
must_be(single_level_list,[Extender|Extenders]),
H = [Extender],
base_extend_part_2([],Extenders,H,T), !.
base_extend(Base,[Extender|Extenders],[H|T]) :-
must_be(single_level_list,Base),
is_list(Base),
must_be(single_level_list,[Extender|Extenders]),
append(Base,[Extender],H),
base_extend_part_2(Base,Extenders,H,T), !.
base_extend(Base,[Extender|Extenders],[H|T]) :-
must_be(single_level_list,Base),
\+ is_list(Base),
must_be(single_level_list,[Extender|Extenders]),
append([Base],[Extender],H),
base_extend_part_2(Base,Extenders,H,T).
base_extend_part_2(_,[],H,[]) :-
must_be(single_level_list,H),!.
base_extend_part_2(Base,Extenders,H,T) :-
base_extend(Base,Extenders,T),
must_be(double_level_list,[H|T]), !.
bases_extend([],_,[]) :- !.
bases_extend([Base|Bases],Extenders,R) :-
must_be(double_level_list,[Base|Bases]),
must_be(single_level_list,Extenders),
base_extend(Base,Extenders,R0),
bases_extend(Bases,Extenders,R1),
append(R0,R1,R),
must_be(double_level_list,R).
combinations_via_extending([],[[]]) :- !.
combinations_via_extending([L1],R) :-
base_extend([],L1,R).
combinations_via_extending([L1,L2],R) :-
bases_extend(L1,L2,R).
combinations_via_extending([L1,L2|T],R) :-
bases_extend(L1,L2,R0),
combinations_via_extending([R0|T],R).
combinations_via_extending(Sets,_) :-
format(', Unmatched Rule @4: ~w',[Sets]).
combinations_via_extending_primer([],[[]]) :- !.
combinations_via_extending_primer([H],R) :-
base_extend([],H,R), !.
combinations_via_extending_primer([H|T],R) :-
base_extend([],H,R0),
combinations_via_extending([R0|T],R), !.
Here are the test cases
:- begin_tests(example_07).
example_07_test_case_generator( 01, [ ] ,[ [] ] ).
example_07_test_case_generator( 02, [ [a] ] ,[ [a] ] ).
example_07_test_case_generator( 03, [ [a,b] ] ,[ [a] ,[b] ] ).
example_07_test_case_generator( 04, [ [a] ,[b] ] ,[ [a,b] ] ).
example_07_test_case_generator( 05, [ [a,b,c] ] ,[ [a] ,[b] ,[c] ] ).
example_07_test_case_generator( 06, [ [a,b] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_07_test_case_generator( 07, [ [a] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_07_test_case_generator( 08, [ [a] ,[b] ,[c] ] ,[ [a,b,c] ] ).
example_07_test_case_generator( 09, [ [a,b,c,d] ] ,[ [a] ,[b] ,[c] ,[d] ] ).
example_07_test_case_generator( 10, [ [a,b,c] ,[d] ] ,[ [a,d] ,[b,d] ,[c,d] ] ).
example_07_test_case_generator( 11, [ [a,b] ,[c,d] ] ,[ [a,c] ,[a,d] ,[b,c] ,[b,d] ] ).
example_07_test_case_generator( 12, [ [a,b] ,[c] ,[d] ] ,[ [a,c,d] ,[b,c,d] ] ).
example_07_test_case_generator( 13, [ [a] ,[b,c] ,[d] ] ,[ [a,b,d] ,[a,c,d] ] ).
example_07_test_case_generator( 14, [ [a] ,[b] ,[c,d] ] ,[ [a,b,c] ,[a,b,d] ] ).
example_07_test_case_generator( 15, [ [a] ,[b] ,[c] ,[d] ] ,[ [a,b,c,d] ] ).
test(1,[condition(true),forall(example_07_test_case_generator(_Test_number,Sets,Expected_result))]) :-
bagof(Es, maplist(member,Es,Sets), Expected_result).
test(2,[condition(true),forall(example_07_test_case_generator(_Test_number,Sets,Expected_result))]) :-
combinations_via_extending_primer(Sets,Expected_result).
:- end_tests(example_07).
Running the tests.
?- run_tests(example_07).
% PL-Unit: example_07 .............................. done
% All 30 tests passed
true.
Here is a more complete example that includes empty sets in the test cases.
remove_empty([],[]) :-
!.
remove_empty([H|T],R) :-
must_be(double_level_list,[H|T]),
H = [],
remove_empty(T,R),
must_be(list,R), % Can be single or double level list
!.
remove_empty([H|T],[H|R]) :-
must_be(double_level_list,[H|T]),
H \= [],
remove_empty(T,R),
must_be(list,R). % Can be single or double level list
:- begin_tests(example_06).
example_06_test_case_generator( 01, [ ] ,[ [] ] ).
example_06_test_case_generator( 02, [ [] ] ,[ [] ] ).
example_06_test_case_generator( 03, [ [] ,[] ] ,[ [] ] ).
example_06_test_case_generator( 04, [ [] ,[] ,[] ] ,[ [] ] ).
example_06_test_case_generator( 05, [ [] ,[] ,[] ,[] ] ,[ [] ] ).
example_06_test_case_generator( 06, [ [a] ] ,[ [a] ] ).
example_06_test_case_generator( 07, [ [a] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 08, [ [] ,[a] ] ,[ [a] ] ).
example_06_test_case_generator( 09, [ [a] ,[] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 10, [ [] ,[a] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 11, [ [] ,[] ,[a] ] ,[ [a] ] ).
example_06_test_case_generator( 12, [ [a] ,[] ,[] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 13, [ [] ,[a] ,[] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 14, [ [] ,[] ,[a] ,[] ] ,[ [a] ] ).
example_06_test_case_generator( 15, [ [] ,[] ,[] ,[a] ] ,[ [a] ] ).
example_06_test_case_generator( 16, [ [a,b] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 17, [ [a,b] ,[] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 18, [ [a] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 19, [ [] ,[a,b] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 20, [ [a] ,[b] ,[] ] ,[ [a,b] ] ).
example_06_test_case_generator( 21, [ [a] ,[] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 22, [ [] ,[a] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 23, [ [a,b] ,[] ,[] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 24, [ [] ,[a,b] ,[] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 25, [ [] ,[] ,[a,b] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 26, [ [a] ,[b] ,[] ,[] ] ,[ [a,b] ] ).
example_06_test_case_generator( 27, [ [a] ,[] ,[b] ,[] ] ,[ [a,b] ] ).
example_06_test_case_generator( 28, [ [a] ,[] ,[] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 29, [ [] ,[a] ,[b] ,[] ] ,[ [a,b] ] ).
example_06_test_case_generator( 30, [ [] ,[a] ,[] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 31, [ [] ,[] ,[a] ,[b] ] ,[ [a,b] ] ).
example_06_test_case_generator( 32, [ [a,b] ,[] ,[] ,[] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 33, [ [] ,[a,b] ,[] ,[] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 34, [ [] ,[] ,[] ,[a,b] ] ,[ [a] ,[b] ] ).
example_06_test_case_generator( 35, [ [a,b,c] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 36, [ [a,b,c] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 37, [ [a,b] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 38, [ [a] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 39, [ [] ,[a,b,c] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 40, [ [a] ,[b,c] ,[] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 41, [ [a] ,[] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 42, [ [a] ,[b] ,[c] ] ,[ [a,b,c] ] ).
example_06_test_case_generator( 43, [ [a,b] ,[c] ,[] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 44, [ [a,b] ,[] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 45, [ [a,b,c] ,[] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 46, [ [] ,[a] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 47, [ [] ,[a,b] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 48, [ [] ,[a,b,c] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 49, [ [] ,[] ,[a,b,c] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 50, [ [a] ,[b,c] ,[] ,[] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 51, [ [a] ,[b] ,[c] ,[] ] ,[ [a,b,c] ] ).
example_06_test_case_generator( 52, [ [a] ,[b] ,[] ,[c] ] ,[ [a,b,c] ] ).
example_06_test_case_generator( 53, [ [a] ,[] ,[b,c] ,[] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 54, [ [a] ,[] ,[b] ,[c] ] ,[ [a,b,c] ] ).
example_06_test_case_generator( 55, [ [a] ,[] ,[] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 56, [ [a,b] ,[c] ,[] ,[] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 57, [ [a,b] ,[] ,[c] ,[] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 58, [ [a,b] ,[] ,[] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 59, [ [a,b,c] ,[] ,[] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 60, [ [] ,[a] ,[b,c] ,[] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 61, [ [] ,[a] ,[b] ,[c] ] ,[ [a,b,c] ] ).
example_06_test_case_generator( 62, [ [] ,[a] ,[] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 63, [ [] ,[a,b] ,[c] ,[] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 64, [ [] ,[a,b] ,[] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 65, [ [] ,[a,b,c] ,[] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 66, [ [] ,[] ,[a] ,[b,c] ] ,[ [a,b] ,[a,c] ] ).
example_06_test_case_generator( 67, [ [] ,[] ,[a,b] ,[c] ] ,[ [a,c] ,[b,c] ] ).
example_06_test_case_generator( 68, [ [] ,[] ,[a,b,c] ,[] ] ,[ [a] ,[b] ,[c] ] ).
example_06_test_case_generator( 69, [ [] ,[] ,[] ,[a,b,c] ] ,[ [a] ,[b] ,[c] ] ).
test(1,[condition(true),forall(example_06_test_case_generator(_Test_number,Sets0,Expected_result))]) :-
remove_empty(Sets0,Sets),
bagof(Es, maplist(member,Es,Sets),Expected_result).
test(2,[condition(true),forall(example_06_test_case_generator(_Test_number,Sets0,Expected_result))]) :-
remove_empty(Sets0,Sets),
combinations_via_extending_primer(Sets,Expected_result).
:- end_tests(example_06).
Running the tests.
?- run_tests(example_06).
% PL-Unit: example_06 .......................................................................................................................................... done
% All 138 tests passed
true
Here is the code for type checking the list.
:- multifile
error:has_type/2.
error:has_type(single_level_list,List) :-
is_one_level_closed_list(List).
error:has_type(double_level_list,List) :-
is_two_level_closed_list(List).
is_one_level_closed_list(List) :-
nonvar(List),
(
List == []
->
true
;
List = [H|T],
(
is_list(H)
->
fail
;
(
T == []
->
true
;
is_one_level_closed_list(T)
)
)
).
is_two_level_closed_list(List) :-
nonvar(List),
(
List == [[]]
->
true
;
List = [H|T],
(
is_one_level_closed_list(H)
->
(
T == []
->
true
;
is_two_level_closed_list(T)
)
;
fail
)
).
Here are the test cases.
:- begin_tests(is_one_level_closed_list).
is_one_level_closed_list_test_case_generator( 01, [] ,true ).
is_one_level_closed_list_test_case_generator( 02, [a] ,true ).
is_one_level_closed_list_test_case_generator( 03, [a,b] ,true ).
is_one_level_closed_list_test_case_generator( 04, [a,b,c] ,true ).
is_one_level_closed_list_test_case_generator( 05, [a,_] ,true ).
is_one_level_closed_list_test_case_generator( 06, [_,a] ,true ).
is_one_level_closed_list_test_case_generator( 07, [_,_] ,true ).
is_one_level_closed_list_test_case_generator( 08, [a|[]] ,true ).
is_one_level_closed_list_test_case_generator( 09, [a,b|[]] ,true ).
is_one_level_closed_list_test_case_generator( 10, [a,b,c|[]] ,true ).
is_one_level_closed_list_test_case_generator( 11, [_|[]] ,true ).
is_one_level_closed_list_test_case_generator( 12, [_,_|[]] ,true ).
is_one_level_closed_list_test_case_generator( 13, [_,_,_|[]] ,true ).
is_one_level_closed_list_test_case_generator( 14, a ,false ).
is_one_level_closed_list_test_case_generator( 15, 1 ,false ).
is_one_level_closed_list_test_case_generator( 16, _ ,false ).
is_one_level_closed_list_test_case_generator( 17, [a|_] ,false ).
is_one_level_closed_list_test_case_generator( 18, [_|a] ,false ).
is_one_level_closed_list_test_case_generator( 19, [_|_] ,false ).
is_one_level_closed_list_test_case_generator( 20, [[]|_] ,false ).
is_one_level_closed_list_test_case_generator( 21, [[]|[]] ,false ).
is_one_level_closed_list_test_case_generator( 22, [[]|a] ,false ).
is_one_level_closed_list_test_case_generator( 23, [a|b] ,false ).
is_one_level_closed_list_test_case_generator( 24, [[]] ,false ).
is_one_level_closed_list_test_case_generator( 25, [a,[]] ,false ).
is_one_level_closed_list_test_case_generator( 26, [[],a] ,false ).
is_one_level_closed_list_test_case_generator( 27, [[],[]] ,false ).
is_one_level_closed_list_test_case_generator( 28, [[],a,b] ,false ).
is_one_level_closed_list_test_case_generator( 29, [a,[],b] ,false ).
is_one_level_closed_list_test_case_generator( 30, [a,b,[]] ,false ).
is_one_level_closed_list_test_case_generator( 31, [[],[],a,b] ,false ).
is_one_level_closed_list_test_case_generator( 32, [[],a,[],b] ,false ).
is_one_level_closed_list_test_case_generator( 33, [[],a,b,[]] ,false ).
is_one_level_closed_list_test_case_generator( 34, [a,[],[],b] ,false ).
is_one_level_closed_list_test_case_generator( 35, [a,[],b,[]] ,false ).
is_one_level_closed_list_test_case_generator( 36, [a,b,[],[]] ,false ).
is_one_level_closed_list_test_case_generator( 37, [[],a,b,c] ,false ).
is_one_level_closed_list_test_case_generator( 38, [a,[],b,c] ,false ).
is_one_level_closed_list_test_case_generator( 39, [a,b,[],c] ,false ).
is_one_level_closed_list_test_case_generator( 40, [a,b,c,[]] ,false ).
test(1,[forall(is_one_level_closed_list_test_case_generator(_Test_number,List,Result))]) :-
(
is_one_level_closed_list(List)
->
Result = true
;
Result = false
).
:- end_tests(is_one_level_closed_list).
:- begin_tests(is_two_level_closed_list).
is_two_level_closed_list_test_case_generator( 01, [[_]] ,true ).
is_two_level_closed_list_test_case_generator( 02, [[a]] ,true ).
is_two_level_closed_list_test_case_generator( 03, [[]] ,true ).
is_two_level_closed_list_test_case_generator( 04, [[_]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 05, [[a]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 06, [[]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 07, [[_],[_]] ,true ).
is_two_level_closed_list_test_case_generator( 08, [[a],[_]] ,true ).
is_two_level_closed_list_test_case_generator( 09, [[_],[a]] ,true ).
is_two_level_closed_list_test_case_generator( 10, [[],[]] ,true ).
is_two_level_closed_list_test_case_generator( 11, [[a],[]] ,true ).
is_two_level_closed_list_test_case_generator( 12, [[],[a]] ,true ).
is_two_level_closed_list_test_case_generator( 13, [[_],[_]] ,true ).
is_two_level_closed_list_test_case_generator( 14, [[],[_]] ,true ).
is_two_level_closed_list_test_case_generator( 15, [[_],[]] ,true ).
is_two_level_closed_list_test_case_generator( 16, [[_],[_]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 17, [[a],[_]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 18, [[_],[a]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 19, [[],[]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 20, [[a],[]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 21, [[],[a]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 22, [[_],[_]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 23, [[],[_]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 24, [[_],[]|[]] ,true ).
is_two_level_closed_list_test_case_generator( 25, [] ,false ).
is_two_level_closed_list_test_case_generator( 26, [a] ,false ).
is_two_level_closed_list_test_case_generator( 27, [a,b] ,false ).
is_two_level_closed_list_test_case_generator( 28, [a,b,c] ,false ).
is_two_level_closed_list_test_case_generator( 29, [a,_] ,false ).
is_two_level_closed_list_test_case_generator( 30, [_,a] ,false ).
is_two_level_closed_list_test_case_generator( 31, [_,_] ,false ).
is_two_level_closed_list_test_case_generator( 32, [a|[]] ,false ).
is_two_level_closed_list_test_case_generator( 33, [a,b|[]] ,false ).
is_two_level_closed_list_test_case_generator( 34, [a,b,c|[]] ,false ).
is_two_level_closed_list_test_case_generator( 35, [_|[]] ,false ).
is_two_level_closed_list_test_case_generator( 36, [_,_|[]] ,false ).
is_two_level_closed_list_test_case_generator( 37, [_,_,_|[]] ,false ).
is_two_level_closed_list_test_case_generator( 38, a ,false ).
is_two_level_closed_list_test_case_generator( 39, 1 ,false ).
is_two_level_closed_list_test_case_generator( 40, _ ,false ).
is_two_level_closed_list_test_case_generator( 41, [a|_] ,false ).
is_two_level_closed_list_test_case_generator( 42, [_|a] ,false ).
is_two_level_closed_list_test_case_generator( 43, [_|_] ,false ).
is_two_level_closed_list_test_case_generator( 44, [[]|_] ,false ).
is_two_level_closed_list_test_case_generator( 45, [[]|a] ,false ).
is_two_level_closed_list_test_case_generator( 46, [a|b] ,false ).
is_two_level_closed_list_test_case_generator( 47, [a,[]] ,false ).
is_two_level_closed_list_test_case_generator( 48, [[],a] ,false ).
is_two_level_closed_list_test_case_generator( 49, [[],a,b] ,false ).
is_two_level_closed_list_test_case_generator( 50, [a,[],b] ,false ).
is_two_level_closed_list_test_case_generator( 51, [a,b,[]] ,false ).
is_two_level_closed_list_test_case_generator( 52, [[],[],a,b] ,false ).
is_two_level_closed_list_test_case_generator( 53, [[],a,[],b] ,false ).
is_two_level_closed_list_test_case_generator( 54, [[],a,b,[]] ,false ).
is_two_level_closed_list_test_case_generator( 55, [a,[],[],b] ,false ).
is_two_level_closed_list_test_case_generator( 56, [a,[],b,[]] ,false ).
is_two_level_closed_list_test_case_generator( 57, [a,b,[],[]] ,false ).
is_two_level_closed_list_test_case_generator( 58, [[],a,b,c] ,false ).
is_two_level_closed_list_test_case_generator( 59, [a,[],b,c] ,false ).
is_two_level_closed_list_test_case_generator( 60, [a,b,[],c] ,false ).
is_two_level_closed_list_test_case_generator( 61, [a,b,c,[]] ,false ).
test(1,[forall(is_two_level_closed_list_test_case_generator(_Test_number,List,Result))]) :-
(
is_two_level_closed_list(List)
->
Result = true
;
Result = false
).
:- end_tests(is_two_level_closed_list).
Running the tests.
?- run_tests(is_one_level_closed_list).
% PL-Unit: is_one_level_closed_list ........................................ done
% All 40 tests passed
true.
?- run_tests(is_two_level_closed_list).
% PL-Unit: is_two_level_closed_list ............................................................. done
% All 61 tests passed
true.
EDIT
To demonstrate that the answers by @false and @repeat do pass the same test cases.
Code by at @false modified slightly to avoid a predicate name collision
list_comb_f(List, Ess) :-
bagof(Es, maplist(member,Es,List), Ess).
Code by @repeat modified slightly to avoid a predicate name collision.
list_comb_r([], [[]]).
list_comb_r([Xs|Xss], Ess) :-
list_comb_r(Xss,Ess0),
maplist(aux_x_comb(Ess0), Xs, Esss1),
append(Esss1, Ess).
aux_x_comb(Ess0, X, Ess1) :-
maplist(head_tail_list(X), Ess0, Ess1).
head_tail_list(X, Xs, [X|Xs]).
Added test using the expanded test cases with empty sets. Note the addition of remove_empty(Sets0,Sets) which is needed for all three answers.
test(3,[condition(true),forall(example_06_test_case_generator(_Test_number,Sets0,Expected_result))]) :-
remove_empty(Sets0,Sets),
list_comb_r(Sets,Result), % repeat answer
assertion( Result == Expected_result ).
test(4,[condition(true),forall(example_06_test_case_generator(_Test_number,Sets0,Expected_result))]) :-
remove_empty(Sets0,Sets),
list_comb_f(Sets,Result), % false answer
assertion( Result == Expected_result ).
Running of tests
?- run_tests(example_06:3).
% PL-Unit: example_06:3 ..................................................................... done
% All 69 tests passed
true.
?- run_tests(example_06:4).
% PL-Unit: example_06:4 ..................................................................... done
% All 69 tests passed
true.
One additional note for those that did not look closely at the answer by @false.
nilmemberd_t([], false).
nilmemberd_t([X|Xs], T) :-
if_(nil_t(X), T = true, nilmemberd_t(Xs, T)).
nil_t([], true).
nil_t([_|_], false).
list_comb_f(List, []) :-
nilmemberd_t(List, true).
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
; T == false -> call(Else_0)
; nonvar(T) -> throw(error(type_error(boolean,T),_))
; /* var(T) */ throw(error(instantiation_error,_))
).
?- list_comb_f(List,[]).
List = [[]|_5808] ;
List = [[_6490|_6492], []|_6498] ;
List = [[_6490|_6492], [_7180|_7182], []|_7188] ;
List = [[_6490|_6492], [_7180|_7182], [_7870|_7872], []|_7878] ;
List = [[_6490|_6492], [_7180|_7182], [_7870|_7872], [_8560|_8562], []|_8568] ;
List = [[_6490|_6492], [_7180|_7182], [_7870|_7872], [_8560|_8562], [_9250|_9252], []|_9258]
...
回答5:
A twist in @false's approach:
%list_comb(++L,-Ess)
list_comb( L, Ess):-
is_list( L),
maplist( is_list, L),
findall( Es, maplist( member, Es, L), Ess).
Testing:
41 ?- list_comb([[1,2],[1],[1]], X). X = [[1, 1, 1], [2, 1, 1]]. 42 ?- list_comb([[1,2],[1],[1,2,3]], X). X = [[1, 1, 1], [1, 1, 2], [1, 1, 3], [2, 1, 1], [2, 1, 2], [2, 1, 3]]. 43 ?- list_comb([[1,2],[],[1,2,3]], X). X = []. 44 ?- list_comb([[1,2],t,[1,2,3]], X). false. 45 ?- list_comb(t, X). false.
来源:https://stackoverflow.com/questions/60580822/combinations-of-multiple-lists-prolog