Prolog列表问题

时间:2009-12-13 20:26:18

标签: merge map list prolog

当我发现这个问题时,我正试图理解prolog中的列表:

谓词mergeandmap / 2基本上应该这样做:

mergeandmap([[a1,...,an],...,[z1,...,zm]],[x1...xn])
            %----------list 1------------ -list 2--

列出2个字母组合(例如[a,b,c])。 列表1包含几个列表,其中size(list2)元素包含1和0    (例如:[[0,0,1],[1,0,1],[0,1,1]])

prolog程序应该从列表1中确定应该打印列表2中的哪些元素以及何时打印。

对于上面的例子:

([[0,0,1],[1,0,1],[0,1,1]],[a,b,c])  Result:  b c abc

另一个例子:

([[0,1,1],[1,0,1],[1,1,1]],[a,b,c])  Result:  bc ac abc
([[0,1],[1,0]],[a,b])  Result:  b a
([[0,1,1,1],[1,0,1,0],[1,1,1,0],[1,1,1,0]],[a,b,c,d])  Result:  bcd acd abcd a

我提出了这个想法:

([[A,B,C],[D,E,F],[G,H,I]],[a,b,c])
  1. “Merge”列出新列表:将所有第一个子元素放在一起,所有第二个子元素,所有第三个元素等等... - > [ADG,BEH,CFI]
  2. “地图”第二个结果列表来自(1):

    [ADG,BEH,CFI] + [abc,abc,abc]

  3. - >大写字母的值决定了小写字母得到的结果。

    有人知道如何在prolog中实现这一点吗? 真的很感激任何帮助!

2 个答案:

答案 0 :(得分:0)

由于每个列表都保证具有相同的长度,因此您可以轻松地细分问题(类似于“分而治之”)。您首先递归遍历您的0/1列表列表,并为每个列表创建相应的输出(再次递归)。

mergeandmap([], _).
mergeandmap([X|Xs], Y) :- helper(X, Y), mergeandmap(Xs, Y).

然后以类似的方式,您可以使用3行编写辅助谓词:基本情况(空列表),0元素和1个元素。由于X和Y都具有相同的长度,因此每个递归谓词都会删除列表的head元素。我认为应该大致了解如何实现这一结果。

顺便说一下,你上面的第一个例子似乎错了。结果应该是c ac bc。

答案 1 :(得分:0)

这是一个你所说的实现,完全按照你的规范在prolog中完成。你的“Merge”实际上是一个名为transpose的函数(在矩阵的上下文中),这恰好出现在SWI-Prolog库中!

1 ?- [user].
|: mergeandmap(Bss,Ls) :- transpose(Bss,BssT), write('Result: '), maptostrings(BssT,Ls), write('\n').
|: maptostrings([],_).
|: maptostrings([Bs|Bss],Ls) :- write(' '), zipstringbits(Bs,Ls), maptostrings(Bss,Ls).
|: zipstringbits([],_).
|: zipstringbits([0|Bs],[_|Ls]) :- zipstringbits(Bs,Ls).
|: zipstringbits([1|Bs],[L|Ls]) :- write(L), zipstringbits(Bs,Ls).
|: :- use_module(library(clpfd)).
%    library(error) compiled into error 0.01 sec, 10,056 bytes
%   library(apply) compiled into apply 0.02 sec, 16,256 bytes
%   library(lists) compiled into lists 0.00 sec, 13,404 bytes
%   library(pairs) compiled into pairs 0.01 sec, 4,772 bytes
%  library(clpfd) compiled into clpfd 0.32 sec, 367,328 bytes
|: 
% user://1 compiled 0.44 sec, 369,348 bytes
true.

2 ?- mergeandmap([[0,0,1],[1,0,1],[0,1,1]],[a,b,c]).
Result:  b c abc
true .

3 ?- mergeandmap([[0,1,1],[1,0,1],[1,1,1]],[a,b,c]).
Result:  bc ac abc
true .

4 ?- mergeandmap([[0,1],[1,0]],[a,b]).
Result:  b a
true .

5 ?- mergeandmap([[0,1,1,1],[1,0,1,0],[1,1,1,0],[1,1,1,0]],[a,b,c,d]).
Result:  bcd acd abcd a
true .

6 ?- mergeandmap([[0,1],[1,0],[1,0]],[a,b,c]).
Result:  bc a
true .

7 ?- transpose([[A,B,C],[D,E,F],[G,H,I]],X).
X = [[A, D, G], [B, E, H], [C, F, I]].

编写自己的转置函数有点复杂,因为我决定自己动手。过了一段时间,我确实设法得到一个非常简洁的解决方案,按照设计,它能够接受列表列表,即使它们不是矩形! (尽管它仍然不如在mergeandmap中使用的那样灵活)。这是代码:

1 ?- [user].
|: transpose(Rs,Cs) :- emptylists(Rs),emptylists(Cs).
|: transpose([[X|R]|Rs],[[X|C]|Cs]) :- headsandtails(Rs,C,NRs), headsandtails(Cs,R,NCs), transpose(NRs,NCs).
|: headsandtails(Xss,[],[]) :- emptylists(Xss).
|: headsandtails([[X|Xs]|Xss],[X|Hs],[Xs|Ts]) :- headsandtails(Xss,Hs,Ts).
|: emptylists([]) :- !.
|: emptylists([[]|L]) :- emptylists(L).
|: 
% user://1 compiled 0.07 sec, 1,208 bytes
true.

2 ?- transpose([[1,2,3,4],[5,6,7],[8,9],[10]],Result).
Result = [[1, 5, 8, 10], [2, 6, 9], [3, 7], [4]] ;
false.

3 ?- transpose([[1,2,3,4],[5,6,7],[8,9,10,11],[10]],Result).
false.

4 ?- transpose([[1,2,3,4,5,7,8,3],[5,6,7],[8,9,10,11],[10]],Result).
false.

5 ?- transpose([[1,2,3,4,5,7,8,3],[5,6,7],[8,9,99],[10]],Result).
Result = [[1, 5, 8, 10], [2, 6, 9], [3, 7, 99], [4], [5], [7], [8], [3]] ;
false.

基本上这是如何工作的,它检查转置的左上角元素和原始元素是否相同,并检查一行的顶行与另一行的左列匹配,反之亦然,然后迭代地检查其他所有内容,直到没有什么可以检查的。

切割操作员!在emptylists谓词上停止使用更多空列表向右增长的答案,并且意味着它可以在尝试转置没有一个的东西时终止(它只是不断添加它们并且始终无法找到答案)。

总结一个解决方案,这就是您需要的所有代码:

mergeandmap(Bss,Ls) :- transpose(Bss,BssT), write('Result: '), maptostrings(BssT,Ls), write('\n').
maptostrings([],_).
maptostrings([Bs|Bss],Ls) :- write(' '), zipstringbits(Bs,Ls), maptostrings(Bss,Ls).
zipstringbits([],_).
zipstringbits([0|Bs],[_|Ls]) :- zipstringbits(Bs,Ls).
zipstringbits([1|Bs],[L|Ls]) :- write(L), zipstringbits(Bs,Ls).
transpose(Rs,Cs) :- emptylists(Rs),emptylists(Cs).
transpose([[X|R]|Rs],[[X|C]|Cs]) :- headsandtails(Rs,C,NRs), headsandtails(Cs,R,NCs), transpose(NRs,NCs).
headsandtails(Xss,[],[]) :- emptylists(Xss).
headsandtails([[X|Xs]|Xss],[X|Hs],[Xs|Ts]) :- headsandtails(Xss,Hs,Ts).
emptylists([]) :- !.
emptylists([[]|L]) :- emptylists(L).