Combinations of multiple lists - Prolog

扶醉桌前 提交于 2020-04-13 06:45:23

问题


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?

  1. 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]].
  2. ... 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]].
  3. ... 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]]].
  4. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!