¿Cómo puedo transponer una lista como [[1,2,3][4,5,6][6,7,8]]
al [[1,4,6],[2,7,8],[3,6,9]]
?Cómo transportar una matriz en el prólogo
Para representarlo: me gustaría voltear la matriz 90 grados hacia la izquierda. ¿Cómo puedo hacer eso?
¿Cómo puedo transponer una lista como [[1,2,3][4,5,6][6,7,8]]
al [[1,4,6],[2,7,8],[3,6,9]]
?Cómo transportar una matriz en el prólogo
Para representarlo: me gustaría voltear la matriz 90 grados hacia la izquierda. ¿Cómo puedo hacer eso?
no está seguro de que su ejemplo es correcta, pero me da la idea.
Si se utiliza SWI-Prolog, puede utilizar la CLPFD module, así:
:- use_module(library(clpfd)).
que le permite utilizar el predicado transpose/2
, así:
1 ?- transpose([[1,2,3],[4,5,6],[6,7,8]], X).
X = [[1, 4, 6], [2, 5, 7], [3, 6, 8]].
De lo contrario (si no hay SWI-PROLOG), simplemente podría usar esta implementación (que resultó ser una antigua en clpfd de SWI):
transpose([], []).
transpose([F|Fs], Ts) :-
transpose(F, [F|Fs], Ts).
transpose([], _, []).
transpose([_|Rs], Ms, [Ts|Tss]) :-
lists_firsts_rests(Ms, Ts, Ms1),
transpose(Rs, Ms1, Tss).
lists_firsts_rests([], [], []).
lists_firsts_rests([[F|Os]|Rest], [F|Fs], [Os|Oss]) :-
lists_firsts_rests(Rest, Fs, Oss).
Para obtener una versión actualizada que utiliza incorporados foldl y maplist, consulte clpfd.pl.
Aquí es a fragment of a larger answer:
% transposed(+A, ?B) iff matrix B is transposed matrix A
transposed(A, B) :- transposed(A, [], B).
transposed(M, X, X) :- empty(M), !.
transposed(M, A, X) :- columns(M, Hs, Ts), transposed(Ts, [Hs|A], X).
% empty(+A) iff A is empty list or a list of empty lists
empty([[]|A]) :- empty(A).
empty([]).
% columns(+M, ?Hs, ?Ts) iff Hs is the first column
% of matrix M and Ts is the rest of matrix M
columns([[Rh|Rt]|Rs], [Rh|Hs], [Rt|Ts]) :- columns(Rs, Hs, Ts).
columns([[]], [], []).
columns([], [], []).
Gracias :) tal vez esto puede ser útil. Primero prefiero usar la función transpose/2, si la hago funcionar de alguna manera ... – cody
un enfoque iterativo:
trans([H|R],[H1|R1]):-trans2([H|R],[H|R],[],[H1|R1],0),!.
trans2([A|_],_,_,[],N):-length(A,N).
trans2(M,[],H1,[H1|R1],N):-N1 is N+1, trans2(M,M,[],R1,N1).
trans2(M,[H|R],L,[H1|R1],N):-nth0(N,H,X),
append(L,[X],L1),trans2(M,R,L1,[H1|R1],N).
Mi solución con nombres completos para una mejor comprensión:
% emptyMatrix(Line, EmptyMatrix)
emptyMatrix([],[]).
emptyMatrix([_|T1],[[]|T2]):-emptyMatrix(T1,T2).
% only length of parameter 'Line' is interesting. It ignores its content.
% appendElement(Element, InputList, OutputList)
appendElement(E,[],[E]).
appendElement(E,[H|T],[H|L]):-appendElement(E,T,L).
% appendTransposed(NestedList, InputMatrix, OutputMatrix)
appendTransposed([],[],[]).
appendTransposed([X|T1],[],[[X]|T3]):-appendTransposed(T1,[],T3).
appendTransposed([X|T1],[R|T2],[C|T3]):-appendElement(X,R,C),appendTransposed(T1,T2,T3).
% transposeMatrix(InputMatrix, TransposedMatrix)
transposeMatrix([L|M],T):-emptyMatrix(L,A),transpose([L|M],T,A).
transpose([],T,T).
transpose([L|M],T,A):-appendTransposed(L,A,B),transpose(M,T,B).
Una 'línea' puede ser una columna o una fila.
La idea consiste en agregar los elementos a las listas de una matriz vacía. (por ejemplo, todos los elementos de la primera fila = los primeros elementos de todos los cols => todos los elementos de la primera fila i-ésimo = los elementos i-ésimo de todos los cols)
Funciona en mi máquina como esta sesión protocolo de muestra para mí:
5 ?- transposeMatrix([[1,2],[3,4]],T).
T = [[1, 3], [2, 4]] ;
false.
6 ?- transposeMatrix([[1],[2]],T).
T = [[1, 2]] ;
false.
7 ?- transposeMatrix([[1,2,3],[4,5,6]],T).
T = [[1, 4], [2, 5], [3, 6]] ;
false.
8 ?- transposeMatrix([[1]],T).
T = [[1]] ;
false.
más simple enfoque:
trans(M, [P|T]):- first(M, P, A), trans(A, T).
trans(Empty, []):- empty(Empty).
empty([[]|T]):- empty(T).
empty([[]]).
first([[P|A]|R], [P|Ps], [A|As]):- first(R, Ps, As).
first([], [], []).
eficiente también
[debug] 36 ?- time(trans([[1,2,3],[4,5,6],[7,8,9]],A)).
% 21 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
A = [[1,4,7],[2,5,8],[3,6,9]] ;
% 12 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
false.
¿Alguna razón para poner los casos más simples al último? – false
No puedo ordenar los resultados. –
Esta es la respuesta más corta que pude encontrar. Sin embargo, podría mejorarse usando listas de diferencias para permitir la recursión final.
transpose([[]|_], []).
transpose(M, [X|T]) :- row(M, X, M1),
transpose(M1, T).
row([], [], []).
row([[X|Xs]|Ys], [X|R], [Xs|Z]) :- row(Ys, R, Z).
Otro enfoque:
delete_one_list([], []).
delete_one_list([[_|L]|LLs], [L|Ls]) :-
delete_one_list(LLs, Ls).
transpose_helper([], []).
transpose_helper([[X|_]|Xs], [X|Ys]) :-
transpose_helper(Xs, Ys).
transpose([[]|_], []).
transpose(List, [L|Ls]) :-
transpose_helper(List, L),
delete_one_list(List, NewList),
transpose(NewList, Ls).
¡Gracias! Estoy usando SWI Prolog y probé tu primera solución. Pero al escribir "use_module (library (clpfd))". Aparece el siguiente error: "ERROR: source_sink" biblioteca (clpfd) 'no existe' ¿Sabes cómo resolver eso? – cody
Supongo que o bien no tiene la biblioteca 'clpfd', o su instalación de SWI-PL está reventada. 'clpfd.pl' debe residir en el directorio' library/clp' (bajo el directorio de inicio de SWI-PL). Si está allí, entonces quizás SWI-PL simplemente no pudo encontrarlo; en este caso, quizás su ejecutable 'pl' tenga un nombre diferente al archivo de configuración' ___. rc', también en el directorio raíz SWI-PL (deben ser idénticos). De lo contrario, simplemente use la definición que he publicado, que es la implementación de 'clpfd'' transpose/2' de todos modos. – sharky
Ok. La biblioteca faltaba y la copié en library/clp. Pero todavía no funciona. Tengo un archivo llamado "plwin.rc" en el directorio pl-root y una carpeta bin con los ejecutables. Mover el archivo .rc a la carpeta bin no lo resuelve ... ¿tengo que modificarlo? – cody