Combinations of multiple lists - Prolog

后端 未结 4 1812
闹比i
闹比i 2020-12-11 20:10

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 ou

相关标签:
4条回答
  • 2020-12-11 20:54

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

    0 讨论(0)
  • 2020-12-11 21:05

    A twist in @false's approach:

    %list_comb( ++LL, -Ess)
    list_comb( LL, Ess):-
        is_list( LL),
        maplist( is_list, LL),
        findall( Es, maplist( member, Es, LL), 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.
    
    0 讨论(0)
  • 2020-12-11 21:12

    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.

    0 讨论(0)
  • 2020-12-11 21:15

    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.
    
    0 讨论(0)
提交回复
热议问题