列出Prolog中矩阵的对角线

时间:2018-01-14 17:50:15

标签: list prolog

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

(我使用内置函数很好。)

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/2diagnal2/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)

使用 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)

虽然原始请求说内置插件很好,但我想找出一个不涉及明确索引列表的解决方案,或使用findallreverseappend并想出了这个:

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).