List 在Prolog中列出矩阵的对角线

List 在Prolog中列出矩阵的对角线,list,prolog,meta-predicate,List,Prolog,Meta Predicate,如何在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]. 我可以使用内置函数。除了长度/2之外,不使用内置谓词的基本解决方案可能是: isSquare([H|T]):- length(H,V), length([H|T],V). diagona

如何在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].

我可以使用内置函数。

除了长度/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]

除了长度/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]
findall/3和其他可能有用的工具:

diagonales(Matrix, [L1, L2]) :-
    length(Matrix, N),
    findall(B, (between(1,N, I), nth1(I, Matrix, Row), nth1(I, Row, B)), L1),
    findall(B, (between(1,N,I), J is N+1-I, nth1(I, Matrix, Row), nth1(J,Row,B)),L2).
findall/3和其他可能有用的工具:

diagonales(Matrix, [L1, L2]) :-
    length(Matrix, N),
    findall(B, (between(1,N, I), nth1(I, Matrix, Row), nth1(I, Row, B)), L1),
    findall(B, (between(1,N,I), J is N+1-I, nth1(I, Matrix, Row), nth1(J,Row,B)),L2).
以下是我使用foldl/4的解决方案:

你能看出对角线1/2和对角线2/2实现的区别吗

在对角线1/2中,我们以与所需顺序相反的顺序返回Res变量中的结果表单foldl/4,因此我们反转结果以获得正确的列表。另一方面,在对角线2/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]. 
以下是我使用foldl/4的解决方案:

你能看出对角线1/2和对角线2/2实现的区别吗

在对角线1/2中,我们以与所需顺序相反的顺序返回Res变量中的结果表单foldl/4,因此我们反转结果以获得正确的列表。另一方面,在对角线2/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]. 

尽管最初的请求中说内置是可以的,但我想找出一个解决方案,它不涉及对列表的显式索引,也不涉及使用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
| ?-
?- 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].

尽管最初的请求中说内置是可以的,但我想找出一个解决方案,它不涉及对列表的显式索引,也不涉及使用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
| ?-
?- 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:

示例查询:

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

示例查询:

| ?- 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
| ?-
?- 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].
对角线[[A]],[[1],[2]]。错误地继承了对角线[[A]]、[[1]、[2]]。错误地成功