En JavaScript las matrices son simplemente vectores de vectores, es decir son vectores donde cada elemento es a su vez un vector (una fila).
Por lo tanto una matriz se crea igual que un vector, es decir de manera formal con new Array o de manera abreviada (la forma recomendada) escribiendo las filas, separadas con comas, entre corchetes. Por ejemplo, la siguiente matriz:
var a = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8]]; a
Como se puede ver, por defecto, la matriz se muestra en una sola línea. Para ver cada fila en una línea diferente, se emplea el método show:
a.show()
Con la forma estándar (que no será empleada en la práctica) la matriz se crea con:
var b = new Array( new Array(1, 2, 3, 4, 5), new Array(2, 3, 4, 5, 6), new Array(3, 4, 5, 6, 7), new Array(4, 5, 6, 7, 8) ); b.show()
Como se mencionó al estudiar vectores, los métodos add, sub, mul, div y neg operan con vectores, matrices, números reales y complejos, por lo que son más generales que los operadores +, -, *, / y - (cuando es empleado como negación). Por ejemplo, dadas las siguientes matrices:
Puenden ser sumadas, restadas, multiplicadas y divididas:
var a = [[2, 8, 2, 3], [1, 6, -1, 4], [2, -1, 2, 5], [4, 2, 3, 5]]; var b = [[1, 4, -2, 3], [2, 2, 0, 4], [3, 0, -1, 2], [1, 2, 2, -3]];
a.add(b).show()
a.sub(b).show()
a.mul(b).show()
a.div(b).round(2).show()
Al ser las matrices vectores de vectores, se pueden emplear todas las propiedades y métodos disponibles para vectores. Adicionalmente, en la calculadora Javascript, se cuenta con los siguientes métodos (librería array):
Métodos de matrices
función
Descripción
identity(n,m)
Crea una matriz identidad con "n" filas y "m" columnas ("n" filas y columnas si sólo se manda "n"), o con las dimensiones de la matriz o vector desde el cual es llamado.
diagonal(k)
Crea una matriz con los elementos del vector desde el cual es llamado, en la diagonal principal o en la diagonal "k".
appendRows(b)
Añade al final de la matriz o vector desde el cual es llamado, las filas de la matriz o vector "b".
appendCols(b)
Añade al final de la matriz o vector desde el cual es llamado, las columnas de la matriz o vector "b"
insertRows(b,k)
Inserta al principio (o en la fila "k") de la matriz o vector desde el cual es llamado, la fila o filas de la matriz o vector "b".
insertCols(b,k)
Inserta al principio (o en la columna "k") de la matriz o vector desde el cual es llamado, la columna o columnas de la matriz o vector "b".
removeRows(k,l)
Quita la fila "k" o las filas "k" a "l" de la matriz o vector desde el cual es llamado, devolviendo la fila o filas removidas.
removeCols(k,l)
Quita la columna "k" o las columnas "k" a "l" de la matriz o vector desde el cual es llamado, devolviendo la columna o columnas removidas.
getRows(k,l)
Devuelve un vector o matriz con la fila "k", o las filas desde "k" hasta "l", de la matriz o vector desde el cual es llamado.
getCols(k,l)
Devuelve un vector o matriz con la columna "k", o las columnas desde "k" hasta "l", de la matriz o vector desde el cual es llamado.
getDiagonal(k)
Devuelve un vector con los elementos de la diagonal principal, o de la diagonal "k", de la matriz desde la cual es llamado.
replaceRows(b,k)
Reemplaza la fila "k", o la fila "k" y posteriores, de la matriz desde la cual es llamdo, con las filas de la matriz o vector "b".
replaceCols(b,k)
Reemplaza la columna "k", o la columna "k" y posteriores, de la matriz desde la cual es llamado, con las columnas de la matriz o vector "b".
rowSwap(i,j)
Intercambia las filas "i" y "j" de la matriz o vector desde el cual es llamado.
colSwap(i,j)
Intercambia las columnas "i" y "j" de la matriz o vector desde el cual es llamado.
det()
Devuelve el determinante de la matriz desde la cual es llamado.
inv()
Devuelve la inversa de la matriz desde la cual es llamado.
trace()
Devuelve el trazo de la matriz desde la cual es llamado.
transpose()
Devuelve una nueva matriz, con la transpuesta de la matriz desde la cual es llamado.
Con estos métodos se pueden llevar a cabo la mayoría de las operaciones requeridas en el trabajo con matrices, además, como se dijo, se pueden emplear también todos los métodos estudiados en vectores.
De estos métodos los que se utilizan con mayor frecuencia en la resolución de sistemas de ecuaciones lineales son inv, transpose y det. De los métodos estudiados previamente, son de mayor utilidad en el trabajo con matrices: rand, const y zeros, además de los métodos de carácter general: copy, round, precision, add, sub, etc.
Se recuerda que, el método rand, genera por defecto un vector o matriz con números realmente aleatorios, es decir con números que se generan en una secuencia no predecible, sin embargo, se pueden generar números pseudoaleatorios (secuencias que pueden volver a ser generadas) estableciendo un valor inicial o semilla (randseed).
Ejemplos
Mostrando las matrices con show:
Genere y guarde en "a" una matriz con 3 filas y 4 columnas de números enteros pseudoaleatorios comprendidos entre 1 y 9 (randseed=1):
randseed = 1; var a = [].rand(3, 4, 1, 9).round(); a.show()
Genere y guarde en "b" una matriz con 4 filas y 4 columnas de números enteros pseudoaleatorios comprendidos entre 1 y 9 (randseed=0):
randseed = 0; var b = [].rand(4, 4, 1, 9).round(); b.show()
Genere y guarde en la variable "c" una matriz con 4 filas y 5 columnas de números 6:
var c = [].const(4, 5, 6); c.show()
Obtenga la transpuesta de la matriz "a":
a.transpose().show()
Calcule la inversa de la matriz b, redondeando los resultados al segundo dígito después del punto:
b.inv().round(2).show()
Calcule la matriz resultante de multiplicar la matriz "a" por la matriz "b":
a.mul(b).show()
Divida la matriz "c" entre el número 2:
c.div(2).show()
Genere una matriz con 4 filas y 6 columnas de ceros:
[].zeros(4, 6).show()
Mostrando las matrices con show y tomando en cuenta las siguientes matrices:
Intercambia la segunda y tercera filas de la matriz "a1":
a1.rowSwap(1, 2).show()
Intercambie la primera y quinta columnas de la matriz "a1":
a1.colSwap(0, 4).show()
Cree el vector "v2" con los elementos de la segunda fila de la matriz "a1":
var v2 = a1.getRows(1); v2
Cree el vector "v3" con los elementos de la cuarta columna de la matriz "a1":
var v3 = a1.getCols(3); v3
Cree el vector "v4" con los elementos de la diagonal principal de la matriz "a1":
var v4 = a1.getDiagonal(); v4
Cree el vector "v5" con los elementos de la primera diagonal a la derecha de la diagonal principal de la matriz "a1":
var v5 = a1.getDiagonal(1); v5
Cree el vector "v6" con los elementos de la segunda diagonal a la izquierda de la diagonal principal de la matriz "a1":
var v6 = a1.getDiagonal(-2); v6
Trabajo con matrices
Al igual que ocurre con vectores, al trabajar con matrices, se llevan a cabo operaciones con todos o un subconjunto de sus elementos. La estructura más adecuada para ese fin (al igual que en vectores) es la estructura for, sólo que con las matrices generalmente se requieren dos estructuras for anidadas (porque tienen dos dimensiones).
Las expresiones matemáticas que involucran sumatorias (\(\sum\)) o productorias (\(\prod\)), pueden ser traducidas directamente a sus estructuras for equivalentes.
Ejemplos
Sumatoria de los elementos de una matriz
Para calcular la sumatoria de los elementos de una matriz, se aplica la siguiente expresión matemática:
\[
S = \sum_{i=1}^{n}\sum_{j=1}^{m}a_{i,j}
\]
Recordando que las matrices en JavaScript comienzan en 0, estas sumatorias pueden ser traducidas directamente en dos ciclos for: El primero (contador "i") desde 0 hasta n-1 y el segundo (contador "j") desde 0 hasta m-1.
Sólo para mayor claridad, se elabora el diagrama de flujo respectivo:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"suma","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matriz de números: a","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"197 130.336211034494"},{"category":"Process","text":"i = 0","key":-2,"loc":"197 -195.33321380615226"},{"category":"Process","text":"i=i+1","key":-7,"loc":"101.99999999999986 -140.9831869125365"},{"category":"Start","text":"fin","key":-9,"loc":"197.0000000000001 183.21402068618664"},{"category":"Process","text":"n = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"m = num. de columnas en a","key":-12,"loc":"197 -304.3999282836913"},{"category":"Process","text":"s = 0","key":-13,"loc":"197 -249.86657104492178"},{"category":"For","text":"i<n","key":-6,"loc":"197 -140.9831869125365"},{"category":"Process","text":"j = 0","key":-14,"loc":"197 -74.63316001892078"},{"category":"Process","text":"j=j+1","key":-15,"loc":"108.99999999999986 -20.283133125305053"},{"category":"For","text":"j<m","key":-16,"loc":"197 -20.28313312530505"},{"category":"Process","text":"s = s+a[i][j]","key":-17,"loc":"197 46.06689376831068"},{"category":"Connector","text":"A","key":-8,"loc":"197 88.02932619494074"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[197,-444.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-434.73332138061517,197,-424.73332138061517]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197,-396.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-376.1999641418456]},{"from":-11,"to":-12,"fromPort":"B","toPort":"T","points":[197,-341.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-321.66660690307606]},{"from":-12,"to":-13,"fromPort":"B","toPort":"T","points":[197,-287.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-277.1332496643065,197,-267.1332496643065]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[197,-232.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-222.59989242553698,197,-212.59989242553698]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[197,-178.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-168.06653518676745,197,-158.06653518676745]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[197,-123.89983863830554,197,-113.89983863830554,197,-107.89983863830554,197,-107.89983863830554,197,-101.89983863830554,197,-91.89983863830554],"text":"Si"},{"from":-16,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[197,-3.1997848510740923,197,6.800215148925908,197,12.800215148925908,197,12.800215148925908,197,18.800215148925908,197,28.800215148925908],"text":"Si"},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[197,-57.36648139953601,197,-47.36648139953601,197,-47.36648139953601,197,-47.36648139953601,197,-47.366481399536006,197,-37.366481399536006]},{"from":-17,"to":-15,"fromPort":"L","toPort":"B","points":[154.55481719970703,46.06689376831068,144.55481719970703,46.06689376831068,108.99999999999986,46.06689376831068,108.99999999999986,26.525219631195196,108.99999999999986,6.9835454940797135,108.99999999999986,-3.0164545059202865]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[133.9778213500975,-20.283133125305053,143.9778213500975,-20.283133125305053,151.67333984374994,-20.283133125305053,151.67333984374994,-20.28313312530505,159.36885833740234,-20.28313312530505,169.36885833740234,-20.28313312530505]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[222.7033462524414,-140.9831869125365,232.7033462524414,-141.49159345626825,281,-141.49159345626825,281,130.336211034494,226.5,130.336211034494,216.5,130.336211034494],"text":"No"},{"from":-4,"to":-9,"fromPort":"B","toPort":"T","points":[197,143.01622537775572,197,153.01622537775572,197,155.4817837222788,197,155.4817837222788,197,157.94734206680192,197,167.94734206680192]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[127.00713348388658,-140.9831869125365,137.00713348388658,-140.9831869125365,149.1518936157226,-140.9831869125365,149.1518936157226,-140.9831869125365,161.2966537475586,-140.9831869125365,171.2966537475586,-140.9831869125365]},{"from":-16,"to":-8,"fromPort":"R","toPort":"R","visible":true,"points":[224.63114166259766,-20.28313312530505,234.63114166259766,-19.141566562652525,257,-19.141566562652525,257,88.02932619494074,221.6957538072453,88.02932619494074,211.6957538072453,88.02932619494074],"text":"No"},{"from":-8,"to":-7,"fromPort":"L","toPort":"L","points":[182.3042461927547,88.02932619494074,172.3042461927547,88.02932619494074,56,88.02932619494074,56,-140.9831869125365,66.99286651611314,-140.9831869125365,76.99286651611314,-140.9831869125365]}]} })
Siendo el código respectivo:
var suma = function(a) { const n = a.length; const m = a[0].length; let s = 0; for (let i=0; i<n; i++) for (let j=0; j<m; j++) s += a[i][j]; return s; };
El número de filas "n" es el número de elementos del array (a.length), porque en una matriz cada fila es un elemento. El número de columnas es el número de elementos en la primera fila (a[0].length, por supuesto asumiendo que es una matriz regular).
var a = [[2, 8, 2, 3], [1, 6, -1, 4], [2, -1, 2, 5], [4, 2, 3, 5]]; var b = [[1, 4, -2, 3], [2, 2, 0, 4], [3, 0, -1, 2], [1, 2, 2, -3]];
suma(a)
suma(b)
Para determinar si una matriz es regular (es decir determinar si todas las filas tienen el mismo número de elementos) se puede llamar al método isMatrixr, que devuelve true (verdadero) si la matriz es regular y false (falso) en caso contrario.
En lugar de la estructura for, el problema puede ser resuelto también empleando la estructura for-of:
var suma_a = function(a) { let s = 0; for (let f of a) for (let e of f) s+=e; return s; };
suma_a(a)
suma_a(b)
En este caso, en el ciclo externo se obtiene en "f", una por una las filas de la matriz "a", mientras que en el interno se obtienen y suman, uno por uno, los elementos "e" de cada fila "f".
Igualmente, el problema puede ser resulto con el método forEach:
var suma_b = function(a) { let s = 0; a.forEach(f=>f.forEach(e=>s+=e)); return s; };
suma_b(a)
suma_b(b)
Donde, al igual que en la estructura for-of, en la llamada externa se obtiene en "f", una por una, las filas de la matriz "a", mientras que en la llamada interna se obtienen y suman, uno por uno, los elementos "e" de cada fila "f".
Igualmente, el problema puede ser resulto con el método map:
var suma_c = function(a) { let s = 0; a.map(f=>f.map(e=>s+=e)); return s; };
suma_c(a)
suma_c(b)
Donde, al igual que en el método anterior, en la llamada externa se obtiene en "f", una por una las filas de la matriz "a", mientras que en la llamada interna se obtienen y suman, uno por uno, los elementos "e" de cada fila "f", sin embargo, como se recordará, map genera una nueva matriz (con las mismas dimensiones que la matriz original) donde cada elemento es igual al resultado de cada una de las llamadas (repeticiones), en este ejemplo las sumatorias parciales de cada una de las filas, sin embargo, en este caso, esa matriz es simplemente descartada (no es empleada), por lo que el método map no es un método eficiente para resolver este tipo de problemas, porque si bien permite calcular el resultado correcto, emplea recursos y tiempo en crear una matriz que en realidad no se requiere.
Empleando el método reduce, el problema se resuelve de la siguiente manera:
var suma_d = function(a) { return a.reduce((s,f)=>s+f.reduce((s,e)=>s+e), 0); };
suma_d(a)
suma_d(b)
En la primera iteración del reduce externo, "s" recibe el número 0 (el valor inicial de la sumatoria) y "f" recibe la primera fila de la matriz. En las posteriores iteraciones del ciclo externo, "s" recibe el resultado de la iteración anterior (la sumatoria de las filas sumadas hasta esa iteración) y "f" recibe la siguiente fila de la matriz.
Por otra parte, en la primera iteración del reduce interno, "s" recibe el primer elemento de la fila "f" (porque el reduce interno no tiene un valor inicial) y "e" recibe el segundo elemento de la fila "f", el cual se suma al primero (a "s"). En las siguientes iteraciones del reduce interno, "s" recibe el resultado de la iteración anterior (la sumatoria de los elementos sumados hasta esa iteración) y "e" es el valor del siguiente elemento de la fila "f".
Es importante tener en mente que, aunque tienen el mismo nombre, el parámetro "s" del reduce interno es diferente al parámetro "s" del reduce externo.
Si no se asignaría el valor inicial 0, al reduce externo, "s" recibiría la primera fila de la matriz y "e" recibiría la sumatoria de la segunda fila, entonces como se debería sumar un vector y un escalar, JavaScript convertiría ambos valores a cadenas (strings) y las concatenaría, de manera que el resultado sería una cadena con los elementos de la primera fila, seguida de las sumatorias de las filas restantes (haga la prueba borrando el valor inicial 1 y llamando al método).
El problema, resuelto con el método every, es:
var suma_e = function(a) { let s = 0; a.every(f=>(f.every(e=>(s+=e,1)),1)); return s; };
suma_e(a)
suma_e(b)
Donde la lógica es la misma que con forEach, pero, para que every itere para todos los elementos de cada una de las filas, la función interna debe devolver 1 (que es uno de los valores que equivalen a true, por supuesto también se puede devolver directamente true).
Igualmente, se puede emplear filter, así como los métodos some, find, findLast, findIndex, findLastIndex, haciendo que, en estos métodos, la función devuelva siempre el valor booleano false o un valor equivalente a false, por ejemplo "0". Sin embargo, como se recalcó en el capítulo anterior, estos métodos no deben ser empleados para resolver problemas reales de este tipo. Se emplean en este y en el anterior capítulo, solo con la finalidad de adquirir práctica en su uso.
Multiplicación de matrices
La siguiente expresión matemática, permite calcular la matriz "c" resultante de multiplicar de dos matrices: "a" y "b":
Donde "nfa" es el número de filas de la matriz "a", "ncb" es el número de columnas de la matriz "b" y "nca" es el número de columnas de la matriz "a". La condición para que dos matrices puedan ser multiplicadas es que el número de columnas de la matriz "a", sea igual al número de filas de la matriz "b".
Esta expresión, puede ser traducida y codificada directamente en tres ciclos for: El primero (contador "i") que va desde 0 hasta nfa-1, el segundo (contador "j") que va desde 0 hasta ncb-1 y el tercero (contador "k") que va desde 0 hasta nca-1.
El diagrama de flujo, es:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"mulMat","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matrices a multiplicar: a, b","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"73.00000000000006 565.9611296749854"},{"category":"Process","text":"i = 0","key":-2,"loc":"72.99999999999996 -38.333213806152244"},{"category":"Process","text":"i=i+1","key":-7,"loc":"-19.000000000000192 16.016813087463447"},{"category":"Start","text":"fin","key":-9,"loc":"197.38115692138683 608.8389393266784"},{"category":"Process","text":"nfa = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"nca = num. de columnas en a","key":-12,"loc":"197 -249.39992828369134"},{"category":"Process","text":"c = []","key":-13,"loc":"73 -92.86657104492167"},{"category":"For","text":"i<nfa","key":-6,"loc":"73.00000000000003 16.01681308746347"},{"category":"Process","text":"j = 0","key":-14,"loc":"73.00000000000007 136.36683998107924"},{"category":"Process","text":"j=j+1","key":-15,"loc":"-19.000000000000185 190.71686687469503"},{"category":"For","text":"j<ncb","key":-16,"loc":"72.99999999999989 190.71686687469494"},{"category":"Process","text":"c[i][j] = c[i][j]+a[i][k]*b[k][j]","key":-17,"loc":"73.00000000000009 432.3003047943116"},{"category":"Process","text":"ncb = num. de columnas en b","key":-18,"loc":"197.38115692138678 -194.86657104492173"},{"category":"Conditional","text":"nca!=nfb","key":-19,"loc":"197.38115692138672 -140.00000000000009"},{"category":"Output","text":"lanzar error:\n\"matrices incompatibles\"","key":-5,"loc":"361.99999999999994 189.79999923706063"},{"category":"Process","text":"c[i] = []","key":-20,"loc":"73 82.36683998107921"},{"category":"Process","text":"c[i][j] = 0","key":-21,"loc":"72.99999999999997 257.0668937683107"},{"category":"For","text":"k<nca","key":-22,"loc":"72.99999999999997 365.95027790069616"},{"category":"Process","text":"k=k+1","key":-23,"loc":"-19.000000000000185 365.95027790069605"},{"category":"Process","text":"k = 0","key":-24,"loc":"72.99999999999999 311.6002510070801"},{"category":"Connector","text":"B","key":-27,"loc":"73.00000000000006 513.6542448354323"},{"category":"Connector","text":"A","key":-28,"loc":"73.00000000000006 474.26273722094174"},{"category":"Process","text":"nfb = num. de filas en b","key":-29,"loc":"197.76231384277344 -304.3999282836912"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[196.99999999999997,-444.73332138061494,196.99999999999997,-434.73332138061494,197,-434.73332138061494,197,-434.7333213806152,197.00000000000006,-434.7333213806152,197.00000000000006,-424.7333213806152]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197.00000000000006,-396.19996414184567,197.00000000000006,-386.19996414184567,197.00000000000006,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418455,197,-376.1999641418455]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[72.99999999999997,-75.59989242553698,72.99999999999997,-65.59989242553698,72.99999999999999,-65.59989242553698,72.99999999999999,-65.59989242553708,73,-65.59989242553708,73,-55.59989242553708]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[73,-21.066535186767545,73,-11.066535186767545,73,-11.066535186767517,73.00000000000003,-11.066535186767517,73.00000000000003,-11.066535186767489,73.00000000000003,-1.0665351867674886]},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[73.00000000000006,153.633518600464,73.00000000000006,163.633518600464,72.99999999999997,163.633518600464,72.99999999999997,163.633518600464,72.99999999999989,163.633518600464,72.99999999999989,173.633518600464]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[5.9778213500974715,190.71686687469497,15.977821350097472,190.71686687469497,22.884281158447116,190.71686687469497,22.884281158447116,190.71686687469494,29.79074096679676,190.71686687469494,39.79074096679676,190.71686687469494]},{"from":-4,"to":-9,"fromPort":"B","toPort":"L","points":[73.00000000000006,578.6411440182472,73.00000000000006,588.6411440182472,73.00000000000006,588,73.00000000000006,588,73.00000000000006,608.8389393266782,163.82163408067493,608.8389393266782,173.82163408067493,608.8389393266782]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[6.007133483886534,16.01681308746345,16.007133483886534,16.01681308746345,23.558635711669844,16.01681308746345,23.558635711669844,16.01681308746347,31.110137939453153,16.01681308746347,41.11013793945315,16.01681308746347]},{"from":-12,"to":-18,"fromPort":"B","toPort":"T","points":[197,-232.13324966430653,197,-222.13324966430653,197,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-212.1332496643065]},{"from":-19,"to":-13,"fromPort":"L","toPort":"T","visible":true,"points":[137.63391876220703,-140,127.63391876220703,-140,72.99999999999997,-140,72.99999999999997,-130.06662483215325,72.99999999999997,-120.1332496643065,72.99999999999997,-110.1332496643065],"text":"No"},{"from":-19,"to":-5,"fromPort":"R","toPort":"T","visible":true,"points":[257.1283950805664,-140,267.1283950805664,-140,362,-140,362,3.7888685862223213,362,147.57773717244464,362,157.57773717244464],"text":"Si"},{"from":-6,"to":-20,"fromPort":"B","toPort":"T","visible":true,"points":[73.00000000000003,33.100161361694425,73.00000000000003,43.100161361694425,73.00000000000003,49.10016136169445,73,49.10016136169445,73,55.10016136169446,73,65.10016136169446],"text":"Si"},{"from":-20,"to":-14,"fromPort":"B","toPort":"T","points":[73,99.63351860046399,73,109.63351860046399,73.00000000000003,109.63351860046399,73.00000000000003,109.10016136169446,73.00000000000006,109.10016136169446,73.00000000000006,119.10016136169446]},{"from":-16,"to":-21,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999989,207.8002151489259,72.99999999999989,217.8002151489259,72.99999999999989,223.8002151489259,73,223.8002151489259,73,229.8002151489259,73,239.8002151489259],"text":"Si"},{"from":-23,"to":-22,"fromPort":"R","toPort":"L","points":[9.936027526855284,365.95027790069605,19.936027526855284,365.95027790069605,24.06441116332997,365.95027790069605,24.06441116332997,365.95027790069616,28.19279479980466,365.95027790069616,38.19279479980466,365.95027790069616]},{"from":-24,"to":-22,"fromPort":"B","toPort":"T","points":[72.99999999999999,328.86692962646487,72.99999999999999,338.86692962646487,72.99999999999999,338.86692962646504,72.99999999999997,338.86692962646504,72.99999999999997,338.8669296264652,72.99999999999997,348.8669296264652]},{"from":-21,"to":-24,"fromPort":"B","toPort":"T","points":[73,274.3335723876954,73,284.3335723876954,73,284.3335723876954,73,284.3335723876953,72.99999999999999,284.3335723876953,72.99999999999999,294.3335723876953]},{"from":-22,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999997,383.0336261749271,72.99999999999997,393.0336261749271,72.99999999999997,399.033626174927,73.00000000000006,399.033626174927,73.00000000000006,405.0336261749269,73.00000000000006,415.0336261749269],"text":"Si"},{"from":-17,"to":-23,"fromPort":"L","toPort":"L","points":[-18.504814147949162,432.30030479431167,-28.504814147949162,432.30030479431167,-69,432.30030479431167,-69,365.95027790069605,-57.93602752685565,365.95027790069605,-47.93602752685565,365.95027790069605]},{"from":-5,"to":-9,"fromPort":"B","toPort":"R","points":[362,213.00002792358396,362,223.00002792358396,362,220,362,220,362,608.8389393266782,230.94067976209854,608.8389393266782,220.94067976209854,608.8389393266782]},{"from":-18,"to":-19,"fromPort":"B","toPort":"T","points":[197.38115692138672,-177.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-170.03335723876953,197.38115692138672,-170.03335723876953,197.38115692138672,-160.03335723876953]},{"from":-11,"to":-29,"fromPort":"B","toPort":"T","points":[197,-341.666606903076,197,-331.666606903076,197.38115692138672,-331.666606903076,197.38115692138672,-331.666606903076,197.76231384277344,-331.666606903076,197.76231384277344,-321.666606903076]},{"from":-29,"to":-12,"fromPort":"B","toPort":"T","points":[197.76231384277344,-287.13324966430645,197.76231384277344,-277.13324966430645,197.76231384277344,-276.8999282836912,197,-276.8999282836912,197,-276.66660690307606,197,-266.66660690307606]},{"from":-22,"to":-28,"fromPort":"R","toPort":"R","visible":true,"points":[107.80720520019528,365.95027790069616,117.80720520019528,364.9751389503481,177,364.9751389503481,177,474.26273722094174,97.69575380724535,474.26273722094174,87.69575380724535,474.26273722094174],"text":"No"},{"from":-28,"to":-15,"fromPort":"L","toPort":"L","points":[58.30424619275475,474.26273722094174,48.30424619275475,474.26273722094174,52,474.26273722094174,52,474.26273722094174,-81,474.26273722094174,-81,190.71686687469497,-53.97782135009784,190.71686687469497,-43.97782135009784,190.71686687469497]},{"from":-16,"to":-27,"fromPort":"R","toPort":"R","visible":true,"points":[106.20925903320301,190.71686687469494,116.20925903320301,190.85843343734746,195,190.85843343734746,195,513.6542448354323,97.69575380724535,513.6542448354323,87.69575380724535,513.6542448354323],"text":"No"},{"from":-27,"to":-7,"fromPort":"L","toPort":"L","points":[58.30424619275475,513.6542448354323,48.30424619275475,513.8271224177162,-99,513.8271224177162,-99,16.01681308746345,-54.0071334838869,16.01681308746345,-44.0071334838869,16.01681308746345]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[104.8898620605469,16.01681308746347,114.8898620605469,15.908415699005172,216,15.908415699005172,216,565.9611296749856,102.50000000000006,565.9611296749856,92.50000000000006,565.9611296749856],"text":"No"}]} })
Como se puede ver, antes de entrar a los ciclos, se crea la matriz vacía resultante "c". En el primer ciclo se añade, en cada iteración, una fila vacía a la matriz "c", en el segundo ciclo se añade, en cada iteración, un elemento ("c[i][j]"), inicialmente igual a cero, a la fila "i" de la matriz resultante "c" y en el tercer ciclo, se calcula y guarda (en c[i][j]) el valor final de ese elemento (el resultado de multiplicar la fila "i" de la matriz "a" por la columna "j" de la matriz "b").
Observe que la matriz "c" se declara como constante, aunque en el proceso se generan y calculan los elementos de cada una de sus filas. Se procede así porque, como se recordará, las variables que almacenan un vector (y en general cualquier objeto) sólo guardan la dirección de memoria donde se encuentra el vector (o el objeto), no los datos en si y esa dirección es constante (lo que cambian son los datos).
Llamando al método con las siguientes matrices:
var a = [[1, 2, 3], [2, 3, 4], [3, 4, 5] ]; var b = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7] ];
Se obtiene:
mulMat(a,b).show()
El algoritmo puede ser codificado también empleando el método push (en lugar de una sentencia de asignación):
var mulMat_a = function(a,b) { const nfa = a.length; const nfb = b.length; const nca = a[0].length; const ncb = b[0].length; if (nca!==nfb) throw "matrices incompatibles"; const c = []; for (let i=0; i<nfa; i++) { c.push([]); for (let j=0; j<ncb; j++) { c[i].push(0); for (let k=0; k<nca; k++) c[i][j] += a[i][k]*b[k][j]; } } return c; };
mulMat_a(a,b).show()
En lugar de iniciar la matriz resultante "c", como una matriz vacía y añadir las filas y elementos en cada ciclo, puede ser iniciada como una matriz de ceros, con el número de filas de la matriz "a" y el número de columnas de la matriz "b", siendo el diagrama de flujo correspondiente:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"mulMat","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matrices a multiplicar: a, b","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"s","key":-4,"loc":"73.00000000000006 457.9611296749852"},{"category":"Process","text":"i = 0","key":-2,"loc":"72.99999999999996 -38.333213806152244"},{"category":"Process","text":"i=i+1","key":-7,"loc":"-19.000000000000192 16.016813087463447"},{"category":"Start","text":"fin","key":-9,"loc":"197.38115692138675 500.8389393266784"},{"category":"Process","text":"nfa = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"nca = num. de columnas en a","key":-12,"loc":"197 -249.39992828369134"},{"category":"Process","text":"c = [].zeros(nfa,ncb)","key":-13,"loc":"73 -92.86657104492167"},{"category":"For","text":"i<nfa","key":-6,"loc":"73.00000000000003 16.01681308746347"},{"category":"Process","text":"j = 0","key":-14,"loc":"73.00000000000003 82.36683998107924"},{"category":"Process","text":"j=j+1","key":-15,"loc":"-19.000000000000178 136.71686687469506"},{"category":"For","text":"j<ncb","key":-16,"loc":"72.99999999999991 136.71686687469497"},{"category":"Process","text":"c[i][j] = c[i][j]+a[i][k]*b[k][j]","key":-17,"loc":"73.00000000000009 324.30030479431196"},{"category":"Process","text":"ncb = num. de columnas en b","key":-18,"loc":"197.38115692138678 -194.86657104492173"},{"category":"Conditional","text":"nca!=nfb","key":-19,"loc":"197.38115692138672 -140.00000000000009"},{"category":"Output","text":"lanzar error:\n\"matrices incompatibles\"","key":-5,"loc":"361.99999999999994 189.79999923706063"},{"category":"For","text":"k<nca","key":-22,"loc":"72.99999999999994 257.9502779006959"},{"category":"Process","text":"k=k+1","key":-23,"loc":"-19.000000000000185 257.9502779006962"},{"category":"Process","text":"k = 0","key":-24,"loc":"73.00000000000001 203.60025100707998"},{"category":"Connector","text":"B","key":-27,"loc":"73.00000000000003 405.6542448354321"},{"category":"Connector","text":"A","key":-28,"loc":"73.00000000000003 366.2627372209418"},{"category":"Process","text":"nfb = num. de filas en b","key":-29,"loc":"197.76231384277344 -304.3999282836912"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[196.99999999999997,-444.73332138061494,196.99999999999997,-434.73332138061494,197,-434.73332138061494,197,-434.7333213806152,197.00000000000006,-434.7333213806152,197.00000000000006,-424.7333213806152]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197.00000000000006,-396.19996414184567,197.00000000000006,-386.19996414184567,197.00000000000006,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418455,197,-376.1999641418455]},{"from":-13,"to":-2,"fromPort":"B","toPort":"T","points":[73,-75.59989242553686,73,-65.59989242553686,72.99999999999997,-65.59989242553686,72.99999999999997,-65.599892425537,72.99999999999996,-65.599892425537,72.99999999999996,-55.59989242553701]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[73,-21.066535186767545,73,-11.066535186767545,73,-11.066535186767517,73.00000000000003,-11.066535186767517,73.00000000000003,-11.066535186767489,73.00000000000003,-1.0665351867674886]},{"from":-14,"to":-16,"fromPort":"B","toPort":"T","points":[73.00000000000007,99.63351860046401,73.00000000000007,109.63351860046401,72.99999999999997,109.63351860046401,72.99999999999997,109.63351860046399,72.99999999999989,109.63351860046399,72.99999999999989,119.63351860046399]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[5.9778213500974715,136.71686687469503,15.977821350097472,136.71686687469503,22.884281158447116,136.71686687469503,22.884281158447116,136.71686687469494,29.79074096679676,136.71686687469494,39.79074096679676,136.71686687469494]},{"from":-4,"to":-9,"fromPort":"B","toPort":"L","points":[73.00000000000009,470.64114401824725,73.00000000000009,480.64114401824725,73.00000000000009,500.83893932667826,118.4108170403375,500.83893932667826,163.82163408067493,500.83893932667826,173.82163408067493,500.83893932667826]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[6.007133483886534,16.01681308746345,16.007133483886534,16.01681308746345,23.558635711669844,16.01681308746345,23.558635711669844,16.01681308746347,31.110137939453153,16.01681308746347,41.11013793945315,16.01681308746347]},{"from":-12,"to":-18,"fromPort":"B","toPort":"T","points":[197,-232.13324966430653,197,-222.13324966430653,197,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-222.1332496643065,197.38115692138672,-212.1332496643065]},{"from":-19,"to":-13,"fromPort":"L","toPort":"T","visible":true,"points":[137.63391876220703,-140.00000000000009,127.63391876220703,-140.00000000000009,73,-140.00000000000009,73,-130.06662483215325,73,-120.1332496643064,73,-110.1332496643064],"text":"No"},{"from":-19,"to":-5,"fromPort":"R","toPort":"T","visible":true,"points":[257.1283950805664,-140,267.1283950805664,-140,362,-140,362,3.7888685862223213,362,147.57773717244464,362,157.57773717244464],"text":"Si"},{"from":-23,"to":-22,"fromPort":"R","toPort":"L","points":[9.936027526855284,257.95027790069605,19.936027526855284,257.95027790069605,24.06441116332997,257.95027790069605,24.06441116332997,257.95027790069616,28.19279479980466,257.95027790069616,38.19279479980466,257.95027790069616]},{"from":-24,"to":-22,"fromPort":"B","toPort":"T","points":[72.99999999999999,220.86692962646484,72.99999999999999,230.86692962646484,72.99999999999999,230.86692962646504,72.99999999999997,230.86692962646504,72.99999999999997,230.8669296264652,72.99999999999997,240.8669296264652]},{"from":-22,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999997,275.0336261749271,72.99999999999997,285.0336261749271,72.99999999999997,291.033626174927,73.00000000000009,291.033626174927,73.00000000000009,297.03362617492684,73.00000000000009,307.03362617492684],"text":"Si"},{"from":-17,"to":-23,"fromPort":"L","toPort":"L","points":[-18.504814147949133,324.3003047943116,-28.504814147949133,324.3003047943116,-57.93602752685565,324.3003047943116,-57.93602752685565,291.12529134750383,-57.93602752685565,257.95027790069605,-47.93602752685565,257.95027790069605]},{"from":-5,"to":-9,"fromPort":"B","toPort":"R","points":[361.99999999999994,213.00002792358407,361.99999999999994,223.00002792358407,361.99999999999994,220,361.99999999999994,220,361.99999999999994,500.83893932667826,230.94067976209854,500.83893932667826,220.94067976209854,500.83893932667826]},{"from":-18,"to":-19,"fromPort":"B","toPort":"T","points":[197.38115692138672,-177.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-167.59989242553698,197.38115692138672,-170.03335723876953,197.38115692138672,-170.03335723876953,197.38115692138672,-160.03335723876953]},{"from":-11,"to":-29,"fromPort":"B","toPort":"T","points":[197,-341.666606903076,197,-331.666606903076,197.38115692138672,-331.666606903076,197.38115692138672,-331.666606903076,197.76231384277344,-331.666606903076,197.76231384277344,-321.666606903076]},{"from":-29,"to":-12,"fromPort":"B","toPort":"T","points":[197.76231384277344,-287.13324966430645,197.76231384277344,-277.13324966430645,197.76231384277344,-276.8999282836912,197,-276.8999282836912,197,-276.66660690307606,197,-266.66660690307606]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[73.00000000000003,33.100161361694425,73.00000000000003,43.100161361694425,73.00000000000003,49.10016136169445,73.00000000000007,49.10016136169445,73.00000000000007,55.100161361694475,73.00000000000007,65.10016136169448],"text":"Si"},{"from":-16,"to":-24,"fromPort":"B","toPort":"T","visible":true,"points":[72.99999999999989,153.8002151489259,72.99999999999989,163.8002151489259,72.99999999999989,170.0668937683106,72.99999999999999,170.0668937683106,72.99999999999999,176.3335723876953,72.99999999999999,186.3335723876953],"text":"Si"},{"from":-22,"to":-28,"fromPort":"R","toPort":"R","visible":true,"points":[107.80720520019528,257.95027790069616,117.80720520019528,257.3751481056215,172,257.3751481056215,172,366.2627372209417,97.69575380724538,366.2627372209417,87.69575380724538,366.2627372209417],"text":"No"},{"from":-28,"to":-15,"fromPort":"L","toPort":"L","points":[58.30424619275478,366.2627372209417,48.30424619275478,365.0313777657443,-71,365.0313777657443,-71,136.71686687469503,-53.97782135009784,136.71686687469503,-43.97782135009784,136.71686687469503]},{"from":-16,"to":-27,"fromPort":"R","toPort":"R","visible":true,"points":[106.20925903320301,136.71686687469494,116.20925903320301,136.7584425926209,186,136.7584425926209,186,405.6542448354323,97.69575380724538,405.6542448354323,87.69575380724538,405.6542448354323],"text":"No"},{"from":-27,"to":-7,"fromPort":"L","toPort":"L","points":[58.30424619275478,405.6542448354323,48.30424619275478,405.4271285212318,-87,405.4271285212318,-87,16.016813087463447,-54.00713348388691,16.016813087463447,-44.00713348388691,16.016813087463447]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[104.8898620605469,16.01681308746347,114.8898620605469,17.20840349197392,205,17.20840349197392,205,457.9611296749855,102.50000000000009,457.9611296749855,92.50000000000009,457.9611296749855],"text":"No"}]} })
Siendo el código respectivo:
var mulMat_b = function(a,b) {
const nfa = a.length;
const nfb = b.length;
const nca = a[0].length;
const ncb = b[0].length;
if (nca!==nfb) throw "matrices incompatibles";
const c = [].zeros(nfa,ncb);
for (let i=0; i<nfa; i++) {
for (let j=0; j<ncb; j++) {
for (let k=0; k<nca; k++) c[i][j] += a[i][k]*b[k][j];
}
}
return c;
};
mulMat_b(a,b).show()
Aunque no es la estructura más adecuada para este caso, el problema puede ser resuelto, también, con la estructura for-of.
Para resolver el problema con la estructura for-of, así como con los métodos iterativos disponibles para el trabajo con matrices, se debe comprender muy bien que, en la multiplicación de dos matrices, cada uno de los elementos de la matriz resultante ("c") es el resultado de multiplicar y sumar (uno a uno) los elementos de cada una de las filas de la matriz "a", por cada uno de los elementos de las columnas de la matriz "b" (por eso el número de columnas de la matriz "a" tiene que ser igual al número de filas de la matriz "b").
Por ejemplo, para obtener el tercer elemento de la segunda fila (el elemento c[1][2]), a partir de las matrices "a" y "b" del ejemplo, se multiplican y suman (uno a uno) los elementos de la segunda fila de la matriz "a" ([2,3,4]), con los elementos de la tercera columna de la matriz "b" ([3,4,5]), es decir:
2*3+3*4+4*5
Entonces, si "fa" es la fila de la matriz "a" y "cb" es la columna de la matriz "b", el elemento resultante, puede ser calculado en un ciclo:
var fa = [2, 3, 4]; var cb = [3, 4, 5]; var s = 0; for (let k=0; k<fa.length; k++) s += fa[k]*cb[k]; s
En consecuencia, para obtener la primera fila de la matriz resultante, se debe multiplicar la primera columna de la matriz "a", por cada una de las columnas de la matriz "b", luego, para la segunda fila, se multiplica la segunda fila de la matriz "a" por cada una de las columnas de la matriz "b" y así sucesivamente.
Como al multiplicar las matrices se trabaja con las columnas de la matriz "b", pero los métodos iteran a través de las filas (no las columnas), para resolver el problema, empleando los métodos iterativos, se debe trabajar con la transpuesta de la matriz "b".
Una vez comprendido el procedimiento, se puede resolver el problema con la estructura for-of:
var mulMat_c = function(a,b) {
b = b.transpose();
if (a[0].length!==b[0].length) throw "matrices incompatibles";
let c=[].zeros(a.length, b.length), i=0, j=0, k=0;
for (const fa of a) {
for (const cb of b) {
for(const ea of fa) c[i][j]+=ea*cb[k++];
j++; k=0;
}
i++; j=0;
}
return c;
};
mulMat_c(a,b).show()
En esta solución, en el primer ciclo (el ciclo externo) se itera para cada una de las filas "fa" de la matriz "a". En el segundo ciclo (el primer ciclo anidado) se itera para cada una de las columnas "cb" de la matriz "b" (porque se está trabajando con la matriz transpuesta) y en el tercer ciclo (el ciclo más interno) se itera para cada uno de los elementos "ea" de cada una de las filas "fa" de la matriz "a".
Antes del primer ciclo se crean la matriz resultante "c" (con valores iguales a cero) y se inician los contadores "i", "j" y "k" en cero. Los contadores "i" y "j" se incrementan al final del ciclo externo e interno y el contador "k" en el ciclo más interno, inmediatamente después de ser usado. El contador "k" se reinicia en 0 al final del ciclo interno (para la siguiente repetición del ciclo más interno) y "j" al final del ciclo externo (para la siguiente repetición del ciclo interno).
Siguiendo un razonamiento similar, el problema puede ser resuelto, igualmente, con los métodos iterativos disponibles para arrays. Así, empleando el método forEach, el problema se resuelve con:
var mulMat_d = function(a,b) {
b = b.transpose();
if (a[0].length!==b[0].length) throw "matrices incompatibles";
const c = [].zeros(a.length, b.length);
a.forEach((fa,i)=>{
b.forEach((cb,j)=>{
fa.forEach((ea,k)=>c[i][j]+=ea*cb[k]);
});
});
return c;
};
mulMat_d(a,b).show()
En este caso, como la función forEach puede recibir también el contador (el índice del elemento) no es necesario declarar, iniciar, incrementar ni reiniciar los contadores.
De manera similar, se pueden emplear los otros métodos, por ejemplo, con el método some, el código, es:
var mulMat_f = function(a,b) {
b = b.transpose();
if (a.length!==b.length) throw new Error("matrices incompatibles");
const c = [].zeros(a.length, b.length);
a.some((fa,i)=>(
b.some((cb,j)=>(
fa.some((ea,k)=>(c[i][j]+=ea*cb[k], 0)), 0)),
0));
return c;
};
mulMat_f(a,b).show()
Donde, para garantizar que el método some itere con todos los elementos, se debe hacer que las funciones devuelvan false o un valor equivalente (en este ejemplo 0). Además, para evitar escribir el comando return, las instrucciones se escriben entre paréntesis (y se separan con comas), de esa manera son ejecutadas como si se tratar de una sola instrucción, siendo el último valor (en este caso 0) el resultado de la función.
Rotar las columnas de una matriz
En este ejemplo se elabora un método que rota, hacia la derecha, las columnas de la matriz desde la cual es llamado.
Para rotar las columnas de una matriz hacia la derecha, dado que las matrices están conformadas por vectores fila, no por vectores columna, es necesario mover, uno a uno, el penúltimo elemento de cada fila una posición hacia la derecha, luego hacer lo mismo con el antepenúltimo elemento y así hasta mover el primer elemento de cada fila a la segunda posición. Como en ese proceso se pierde el último elemento de cada fila (pues es reemplazado por el penúltimo), es necesario, antes de comenzar el proceso, guardar ese elemento (en una variable auxiliar) y una vez movidos los elementos, reemplazar el primer elemento de cada fila, por el valor guardado (para que el último elemento de cada fila pase a ser el primero).
El diagrama de flujo correspondiente al algoritmo explicado, es:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"rotarcd","key":-1,"loc":"197.00000000000003 -459.9999999999999"},{"category":"Input","text":"matriz de números: a","key":-3,"loc":"197 -410.46664276123033"},{"category":"Output","text":"a","key":-4,"loc":"197.00000000000014 156.47806065877288"},{"category":"Process","text":"i = 0","key":-2,"loc":"196.99999999999997 -249.33321380615226"},{"category":"Process","text":"i=i+1","key":-7,"loc":"101.99999999999983 -194.98318691253647"},{"category":"Start","text":"fin","key":-9,"loc":"197.00000000000028 209.35587031046575"},{"category":"Process","text":"n = num. de filas en a","key":-11,"loc":"197 -358.9332855224608"},{"category":"Process","text":"m = num. de columnas en a","key":-12,"loc":"197 -304.3999282836913"},{"category":"For","text":"i<n","key":-6,"loc":"197.00000000000003 -194.98318691253652"},{"category":"Process","text":"aux = a[i][m-1]","key":-14,"loc":"197 -128.63316001892082"},{"category":"Process","text":"j=j-1","key":-15,"loc":"108.99999999999987 -19.283133125305064"},{"category":"For","text":"j>0","key":-16,"loc":"196.99999999999994 -19.28313312530505"},{"category":"Process","text":"a[i][j] = a[i][j-1]","key":-17,"loc":"197.00000000000014 47.066893768310656"},{"category":"Process","text":"j = m-1","key":-19,"loc":"197 -75.63316001892082"},{"category":"Process","text":"a[i][0] = aux","key":-20,"loc":"197.00000000000014 101.60025100708019"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[197.00000000000006,-444.7333213806148,197.00000000000006,-434.7333213806148,197.00000000000003,-434.7333213806148,197.00000000000003,-434.7333213806151,197,-434.7333213806151,197,-424.7333213806151]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[197,-396.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-386.1999641418456,197,-376.1999641418456]},{"from":-11,"to":-12,"fromPort":"B","toPort":"T","points":[197,-341.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-331.66660690307606,197,-321.66660690307606]},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[197,-232.06653518676754,197,-222.06653518676754,197,-222.0665351867675,197,-222.0665351867675,197,-222.06653518676745,197,-212.06653518676745]},{"from":-6,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[197,-177.89983863830554,197,-167.89983863830554,197,-161.89983863830557,197.00000000000006,-161.89983863830557,197.00000000000006,-155.8998386383056,197.00000000000006,-145.8998386383056],"text":"Si"},{"from":-16,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[196.99999999999994,-2.1997848510740923,196.99999999999994,7.800215148925908,196.99999999999994,13.800215148925899,197.00000000000014,13.800215148925899,197.00000000000014,19.80021514892589,197.00000000000014,29.80021514892589],"text":"Si"},{"from":-17,"to":-15,"fromPort":"L","toPort":"B","points":[142.12315368652358,47.066893768310656,132.12315368652358,47.066893768310656,108.99999999999987,47.066893768310656,108.99999999999987,27.525219631195178,108.99999999999987,7.983545494079699,108.99999999999987,-2.0164545059203007]},{"from":-15,"to":-16,"fromPort":"R","toPort":"L","points":[132.2699279785155,-19.283133125305067,142.2699279785155,-19.283133125305067,151.7026596069335,-19.283133125305067,151.7026596069335,-19.28313312530505,161.1353912353515,-19.28313312530505,171.1353912353515,-19.28313312530505]},{"from":-6,"to":-4,"fromPort":"R","toPort":"R","visible":true,"points":[222.7033462524414,-194.9831869125365,232.7033462524414,-195.99159345626825,299,-195.99159345626825,299,156.4780606587729,226.50000000000014,156.4780606587729,216.50000000000014,156.4780606587729],"text":"No"},{"from":-4,"to":-9,"fromPort":"B","toPort":"T","points":[197.00000000000014,169.15807500203462,197.00000000000014,179.15807500203462,197.00000000000014,181.6236333465577,197.00000000000014,181.6236333465577,197.00000000000014,184.08919169108083,197.00000000000014,194.08919169108083]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[127.00713348388658,-194.9831869125365,137.00713348388658,-194.9831869125365,149.1518936157226,-194.9831869125365,149.1518936157226,-194.9831869125365,161.2966537475586,-194.9831869125365,171.2966537475586,-194.9831869125365]},{"from":-12,"to":-2,"fromPort":"B","toPort":"T","points":[197,-287.1332496643065,197,-277.1332496643065,197,-276.8665710449218,197,-276.8665710449218,197,-276.59989242553706,197,-266.59989242553706]},{"from":-14,"to":-19,"fromPort":"B","toPort":"T","points":[197,-111.36648139953607,197,-101.36648139953607,197,-101.36648139953607,197,-102.89983863830558,197,-102.89983863830558,197,-92.89983863830558]},{"from":-19,"to":-16,"fromPort":"B","toPort":"T","points":[197,-58.36648139953604,197,-48.36648139953604,197,-47.36648139953603,196.99999999999994,-47.36648139953603,196.99999999999994,-46.366481399536006,196.99999999999994,-36.366481399536006]},{"from":-16,"to":-20,"fromPort":"R","toPort":"R","visible":true,"points":[222.86460876464838,-19.28313312530505,232.86460876464838,-20.141566562652525,276,-20.141566562652525,276,101.60025100708019,252.70703887939467,101.60025100708019,242.70703887939467,101.60025100708019],"text":"No"},{"from":-20,"to":-7,"fromPort":"L","toPort":"L","points":[151.2929611206056,101.60025100708019,141.2929611206056,101.60025100708019,56,101.60025100708019,56,-194.9831869125365,66.99286651611314,-194.9831869125365,76.99286651611314,-194.9831869125365]}]} })
Siendo el código respectivo:
var rotarcd = function(a) { const n = a.length; const m = a[0].length; for (let i=0; i<n; i++) { const aux = a[i][m-1]; for (let j=m-1; j>0; j--) a[i][j] = a[i][j-1]; a[i][0] = aux; } return a; };
Que puede ser probada, por ejemplo, rotando 2 veces una matriz pseudoaleatoria (semilla = 1) de 5 filas y 7 columnas de números enteros comprendidos entre 10 y 30:
randseed = 1; var a = [].rand(5, 7, 20, 30).round(); a.show()
rotarcd(a).show()
rotarcd(a).show()
El problema puede ser resuelto, igualmente, empleando la estructura for-of
var rotarcd_a = function(a) {
const n = a.length;
const m = a[0].length-1;
let aux, k;
for(const f of a) {
aux = f[m]; k = m;
for(let _ of f) f[k] = k===0 ? aux : f[--k];
}
return a;
};
randseed = 1; var a = [].rand(3, 4, 1, 9).round(); a.show()
rotarcd_a(a).show()
rotarcd_a(a).show()
En este caso, el ciclo externo itera para cada una de las filas "f" de la matriz "a". Dentro del ciclo se guarda (en "aux") el último elemento de la fila ("f[m]") y en "k" el índice del último elemento (m). En el ciclo interno, se itera para cada uno de los elementos "_" de la fila "f", los elementos se denominan "_", porque en realidad no son utilizados en la función.
Dentro del ciclo interno, en la primera iteración, se asigna al último elemento: f[k], el penúltimo elemento: f[--k], disminuyendo al mismo tiempo el valor del contador "k", por lo que ahora "k" apunta al penúltimo elemento. Entonces en la segunda iteración se asigna el antepenúltimo elemento al penúltimo y así, sucesivamente, hasta que en la última iteración (cuando "k" es igual a cero) se asigna al primer elemento (f[0]) el valor del último elemento ("aux") con lo que la fila queda rotada.
Con un razonamiento similar, se pueden emplear también otros métodos iterativos. Por ejemplo con el método every, el código que resuelve el problema, es:
var rotarcd_b = function(a) {
const n = a.length;
const m = a[0].length-1;
let aux;
a.every(f=>(
aux = f[m],
f.every((_,k)=>(f[m-k] = k===m ? aux : f[m-k-1], 1)),
1
));
return a;
};
randseed = 1; var a = [].rand(3, 4, 1, 9).round(); a.show()
rotarcd_b(a).show()
rotarcd_b(a).show()
Donde, al igual que con some y por la misma razón, las funciones se escriben entre paréntesis, sólo que ahora se devuelve un valor equivalente a true (1).
En el ciclo interno, como "k" comienza en 0 y se necesita apuntar al último elemento (no al primero), los índices se calculan con m-k, para que en la primera iteración sea el último elemento: m-0 = m, en la siguiente el penúltimo: m-1 y así sucesivamente. Pero, cuando se llega al primer elemento (cuando "k" es igual a "m": m-m = 0), se asigna el valor del último elemento (aux), por eso en la función se pregunta si "m" es igual a "k" y de ser así, se le asigna el valor de "aux".
Si el problema consiste en rotar las filas de la matriz, no las columnas, solo se requiere un ciclo (no dos) porque en una matriz, las filas son simplemente los elementos de la matriz, en consecuencia, el problema se reduce a rotar los elementos de un vector.