问题
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
a
before[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