如何在Prolog中获得大小为n*n
的矩阵的对角线列表?
预期行为:
?- diagonal1([[1,3,2],[4,5,7],[6,8,9]],D1).
D1=[1,5,9]
?- diagonal2([[1,3,2],[4,5,7],[6,8,9]],D2).
D2=[2,5,6].
(我使用内置函数很好。)
答案 0 :(得分:7)
以下是foldl/4
的解决方案:
extract_element(L, L1, [H|L1]):-
length(L1, N1),
length(L2, N1),
append(L2, [H|_], L).
diagonal1(In, Out):-
foldl(extract_element, In, [], Res),
reverse(Res,Out).
diagonal2(In, Out):-
reverse(In, In2),
foldl(extract_element, In2, [], Out).
您能看到diagonal1/2
和diagnal2/2
实施中的差异吗?
在diagonal1/2
中,我们在Res变量中以与所需顺序相反的顺序返回结果形式foldl/4
,因此我们反转结果以获得正确的列表。另一方面,在diagonal2/2
中,您通过反转输入列表了解foldl/4
的工作方式,我们不仅能够提取正确的元素,而且现在从foldl/4
返回的逆序是正确!!!!
示例:
?- diagonal1([[1,3,2],[4,5,7],[6,8,9]],D1).
D1 = [1, 5, 9].
?- diagonal2([[1,3,2],[4,5,7],[6,8,9]],D2).
D2 = [2, 5, 6].
答案 1 :(得分:5)
使用meta-predicate maplist/3
和常用的reverse/2
:
list_diag1([], []).
list_diag1([[E|_]|Ess], [E|Ds]) :-
maplist(list_tail, Ess, Ess0),
list_diag1(Ess0, Ds).
list_tail([_|Es], Es).
list_diag2(Ess,Ds) :-
maplist(reverse, Ess, Fss),
list_diag1(Fss, Ds).
示例查询:
?- list_diag1([[a,b,c],[d,e,f],[g,h,i]], D1).
D1 = [a,e,i].
?- list_diag2([[a,b,c],[d,e,f],[g,h,i]], D2).
D2 = [c,e,g].
答案 2 :(得分:3)
虽然原始请求说内置插件很好,但我想找出一个不涉及明确索引列表的解决方案,或使用findall
,reverse
或append
并想出了这个:
diag1(Matrix, Diag) :-
diag1(Matrix, [], Diag).
diag1([], _, []).
diag1([Row|Rows], Fs, [D|Ds]) :-
front_same_length(Fs, D, Row),
diag1(Rows, [_|Fs], Ds).
diag2([Row|Rows], Diag) :-
diag2([Row|Rows], Row, Diag).
diag2([], _, []).
diag2([Row|Rows], [_|Fs], [D|Ds]) :-
front_same_length(Fs, D, Row),
diag2(Rows, Fs, Ds).
front_same_length([], D, [D|_]).
front_same_length([_|Xs], D, [_|Rs]) :-
front_same_length(Xs, D, Rs).
这里的原则是使用front_same_length/3
通过使用另一个已知长度的匿名列表来确定列表内某点的元素。这产生以下结果:
| ?- diag1([[1,2,3],[4,5,6],[7,8,9]], D).
D = [1,5,9]
yes
| ?- diag2([[1,2,3],[4,5,6],[7,8,9]], D).
D = [3,5,7]
yes
| ?- diag1(Matrix, Diag).
Diag = []
Matrix = [] ? ;
Diag = [A]
Matrix = [[A|_]] ? ;
Diag = [A,B]
Matrix = [[A|_],[_,B|_]] ? ;
Diag = [A,B,C]
Matrix = [[A|_],[_,B|_],[_,_,C|_]] ? ;
...
| ?- diag2(Matrix, Diag).
Diag = [A]
Matrix = [[A]] ? ;
Diag = [A]
Matrix = [[_,A]] ? ;
Diag = [A,B]
Matrix = [[_,A],[B|_]] ? ;
Diag = [A]
Matrix = [[_,_,A]] ? ;
Diag = [A,B]
Matrix = [[_,_,A],[_,B|_]] ? ;
Diag = [A,B,C]
Matrix = [[_,_,A],[_,B|_],[C|_]] ? ;
Diag = [A]
Matrix = [[_,_,_,A]] ? ;
...
对于行数小于或等于基于其设计方式的列数的矩阵,似乎表现良好。如果行数超过列数,它将失败。
<小时/> 这是一个更新的解决方案,适用于一般的n x m矩阵,代价是留下一个选择点:
diag1(Matrix, Diag) :-
diag1(Matrix, [], Diag).
diag1([], _, []).
diag1([Row|Rows], Fs, [D|Ds]) :-
front_same_length(Fs, D, Row),
diag1(Rows, [_|Fs], Ds).
diag1([Row|_], Fs, []) :-
same_length(Row, Fs).
diag2([Row|Rows], Diag) :-
diag2([Row|Rows], Row, Diag).
diag2([], _, []).
diag2([Row|Rows], [_|Fs], [D|Ds]) :-
front_same_length(Fs, D, Row),
diag2(Rows, Fs, Ds).
diag2([_|_], [], []).
front_same_length([], D, [D|_]).
front_same_length([_|Xs], D, [_|Rs]) :-
front_same_length(Xs, D, Rs).
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
运行示例查询:
| ?- diag1([[a,b],[c,d]], D).
D = [a,d] ? ;
no
| ?- diag2([[a,b],[c,d]], D).
D = [b,c] ? a
no
| ?- diag1([[a,b,c],[d,e,f],[g,h,i]], D).
D = [a,e,i] ? ;
no
| ?- diag2([[a,b,c],[d,e,f],[g,h,i]], D).
D = [c,e,g] ? ;
no
| ?- diag1([[a,b,c],[d,e,f]], D).
D = [a,e] ? a
no
| ?- diag2([[a,b,c],[d,e,f]], D).
D = [c,e] ? ;
no
| ?- diag1([[a,b,c],[d,e,f],[g,h,i],[j,k,l]], D).
D = [a,e,i] ? ;
no
| ?- diag2([[a,b,c],[d,e,f],[g,h,i],[j,k,l]], D).
D = [c,e,g] ? ;
no
| ?-
答案 3 :(得分:1)
不使用内置谓词(length/2
除外)的基本解决方案可能是:
isSquare([H|T]):-
length(H,V),
length([H|T],V).
diagonal(M,D):-
diagonalA(M,D,1).
diagonalA([],[],_).
diagonalA([H|T],[HD|TD],I):-
diagonalInner(H,HD,I,1),
I1 is I+1,
diagonalA(T,TD,I1).
diagonalInner([H|_],H,I,I):-!.
diagonalInner([_|T],H,I,I1):-
I2 is I1+1,
diagonalInner(T,H,I,I2).
antidiagonal([H|T],A):-
length(H,N),
antidiagonalA([H|T],A,N).
antidiagonalA([],[],0).
antidiagonalA([H|T],[HA|TA],N):-
antidiagonalInner(H,HA,N,1),
N1 is N-1,
antidiagonalA(T,TA,N1).
antidiagonalInner([H|_],H,I,I):-!.
antidiagonalInner([_|T],H,I,E):-
E1 is E+1,
antidiagonalInner(T,H,I,E1).
solve(M,D1,D2):-
isSquare(M),
diagonal(M,D1),
antidiagonal(M,D2).
?- solve([[1,2,3],[4,5,6],[7,8,9]],D1,D2).
D1 = [1, 5, 9],
D2 = [3, 5, 7]
答案 4 :(得分:1)
findall / 3 ,其他可能有用:
Guid
答案 5 :(得分:1)
diag(M,D) :- findall(V, (nth1(I,M,X),nth1(I,X,V)), D).
gaid(M,G) :- length(M,L), findall(V, (nth1(I,M,X),J is L-I+1,nth1(J,X,V)), G).