通过从每个列表中选择1个元素来创建列表(序言)

时间:2018-10-14 11:34:51

标签: prolog

我有一个包含列表的列表。 我想创建一个排列列表。

示例:

generate_perm([[3],[1,2,3,4],[1,2]], P).
P = [[3,1,1], [3,2,1], [3,3,1], [3,4,1], [3,1,2], [3,2,2], [3,3,2], [3,4,2]];
no

因此,输出列表:第n个元素是输入列表中第n个列表的元素。 我已经尝试过的方法:使用member和findall,但是我陷入了困境。因为我是新手,所以我总是必须思考。

到目前为止,我的代码提供了1种解决方案:

generate_perm([],_).
generate_perm([H|Tl], Perm):- member(M, H), append(Perm, [M], Perm2),
                              generate_perm(Tl, Perm2).

调试:

| ?- generate_perm([[3],[1,2,3,4],[1,2]], P).
 #      1      1 Call: member(_4961,[3]) ? 
 #      1      1 Exit: member(3,[3]) ? 
 #      2      1 Call: generate_perm([[1,2,3,4],[1,2]],[3]) ? 
 #      3      2 Call: member(_56173,[1,2,3,4]) ? 
?#      3      2 Exit: member(1,[1,2,3,4]) ? 
 #      4      2 Call: generate_perm([[1,2]],[3,1]) ? 
 #      5      3 Call: member(_138349,[1,2]) ? 
?#      5      3 Exit: member(1,[1,2]) ? 
 #      6      3 Call: generate_perm([],[3,1,1]) ? 
 #      6      3 Exit: generate_perm([],[3,1,1]) ? 
?#      4      2 Exit: generate_perm([[1,2]],[3,1]) ? 
?#      2      1 Exit: generate_perm([[1,2,3,4],[1,2]],[3]) ? 
P = [] ? 

所以答案就在那里(调用:generate_perm([],[3,1,1]),这里答案为[3,1,1]),但是它给了我一个空列表,我可以找出原因。 我需要帮助的另一个步骤是我不知道如何将所有解决方案都放在一个列表中。

1 个答案:

答案 0 :(得分:1)

就像说的那样,“命令式思维”通常与Prolog配合得不太好。您应该考虑(递归)定义。

例如,我们可以说第一个列表为空的crossprod/2产生一个解决方案:空列表,因此我们可以将其指定为:

crossprod([], []).

现在我们仍然需要提出一个归纳案例:给定我们可以为 n-1 个元素的列表生成置换,那么我们应该如何为个列表生成置换呢? > n 个元素(n≥0)。

对于这样的列表,我们在这里有第一个元素(“ head”),即head是一个列表(因为第一个参数应该是列表的列表)。因此,我们可以使用member/2来获取 sub 列表的元素,该元素将成为结果列表的 head (第一项),然后传递尾部(其余子列表)递归到crossprod/2以生成结果的尾部,例如:

crossprod([H|T], [X|R]) :-
    member(X, H),
    crossprod(T, R).

或全部,它给出:

crossprod([], []).
crossprod([H|T], [X|R]) :-
    member(X, H),
    crossprod(T, R).

因此,现在我们可以生成给定“集合”列表的“叉积”项,例如:

?- crossprod([[3],[1,2,3,4],[1,2]], P).
P = [3, 1, 1] ;
P = [3, 1, 2] ;
P = [3, 2, 1] ;
P = [3, 2, 2] ;
P = [3, 3, 1] ;
P = [3, 3, 2] ;
P = [3, 4, 1] ;
P = [3, 4, 2].

如果我们随后要生成这些列表(这很奇怪,通常最好独立生成答案),则可以使用findall/3

generate_perm(S,R):-     findall(Ri,crossprod(S,Ri),R)。

然后获得交叉产品列表,例如:

?- generate_perm([[3],[1,2,3,4],[1,2]], P).
P = [[3, 1, 1], [3, 1, 2], [3, 2, 1], [3, 2, 2], [3, 3, 1], [3, 3, 2], [3, 4|...], [3|...]].