当我发现这个问题时,我正试图理解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):
[ADG,BEH,CFI] + [abc,abc,abc]
- >大写字母的值决定了小写字母得到的结果。
有人知道如何在prolog中实现这一点吗? 真的很感激任何帮助!
答案 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).