0
\$\begingroup\$

I needed to rotate a non-square matrix in my program to transpose some spreadsheet data and decided to make a function to rotate 90, 180, or 270 degrees.

It doesn't rotate the matrix in place, but instead generates a copy and returns that. I want to go for processing efficiency, let me know what I can do better:

//Rotates the provided matrix by provided degrees counterclockwise
function RotateMatrix(matrix, degrees){ 
 if(degrees == 90){
 //For 90 degrees swap the height/width and swap the location of each element
 var output = GenerateMatrix(matrix[0].length, matrix.length, 0); //Swapping the width and height for non square matrices
 for(var i = 0; i < matrix[0].length; i++){
 for(var j = 0; j < matrix.length; j++){
 output[i][j] = matrix[j][i];
 }
 } 
 } else if(degrees == 180) {
 //For 180 degrees, rebuild array backwards
 var output = GenerateMatrix(matrix.length, matrix[0].length, 0);
 for(var i = matrix.length - 1; i >= 0; i--){
 for(var j = matrix[0].length - 1; j >=0; j--){
 output[matrix.length - 1 - i][matrix[0].length - 1 - j] = matrix[i][j];
 }
 } 
 } else if(degrees == 270) {
 //For 270 degrees, not sure how to make short description
 var output = GenerateMatrix(matrix[0].length, matrix.length, 0); //Swapping the width and height for non square matrices
 for(var i = 0; i < matrix[0].length; i++){
 for(var j = matrix.length - 1; j >=0; j--){
 output[i][matrix.length - 1 - j] = matrix[j][i];
 }
 } 
 } 
 return output;
}
//Generates a matrix with the requested length and width and value
function GenerateMatrix(length, width, value){
 var output = [];
 for(var i = 0; i < length; i++){
 width > 0 ? output.push([]) : output.push(value); //If matrix has 0 width
 for(var j = 0; j < width; j++){
 output[i].push(value)
 }
 }
 return output;
}
asked Apr 10, 2016 at 22:34
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Unnecessary matrix generation

In JavaScript, Arrays don't have a fixed size. For example, you could do this:

var arr = [];
arr[324] = 91;

with no problem.

Your GenerateMatrix function is really over-doing it. All you need to do is create the arrays for the rows/columns then change their values.

And, you can do that with a neat trick:

Array.apply(null, Array(rowCount)).map(function(){return []});
answered Apr 10, 2016 at 23:20
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the reply. I've typically programmed in C#, so JS is pretty new to me. That's good to know that I don't need to generate the "blank" array first. I initially avoided map due to the performance hit, looping ended up being more performance friendly when this is being executed in a cloud environment with very limited processing time. \$\endgroup\$ Commented Apr 10, 2016 at 23:55
1
\$\begingroup\$

Here's a version to where it does not flip, but instead reads or writes into the correct location. Fastest way I know to "rotate" it, but does add some overhead when reading and writing.

function addC(row, i) {
 Object.defineProperty(row.self, i, {
 get: function() { 
 if(!(row.matrix.degrees % 360)) {
 return row.data[i];
 }
 else if(!(row.matrix.degrees % 270)) {
 }
 else if(!(row.matrix.degrees % 180)) {
 }
 else if(!(row.matrix.degrees % 90)) {
 return row.matrix.rows[i].data[row.matrix.column];
 }
 },
 set: function(v) { 
 if(!(row.matrix.degrees % 360)) {
 row.data[i] = v;
 }
 else if(!(row.matrix.degrees % 270)) {
 }
 else if(!(row.matrix.degrees % 180)) {
 }
 else if(!(row.matrix.degrees % 90)) {
 row.matrix.rows[i].data[row.matrix.column] = v;
 }
 },
 enumerable: true
 });
}
function Row(matrix) {
 var members = {
 self: this,
 matrix: matrix,
 data: {}
 }
 for(var i = matrix.width; i--;) {
 addC(members, i);
 }
 Object.defineProperty(members.self, "data", { value: members.data });
}
function addR(matrix, i) {
 matrix.rows[i] = new Row(matrix);
 Object.defineProperty(matrix.self, i, {
 get: function() { matrix.column = i; return matrix.rows[i]; },
 enumerable: true
 });
}
function Matrix(width, height) {
 var members = {
 self: this,
 width: width,
 height: height,
 degrees: 0,
 column: -1,
 rows: {}
 };
 for(var i = height; i--;) {
 addR(members, i);
 }
 Object.defineProperty(members.self, "degrees", { value: function(v) {
 if(v === undefined) return members.degrees;
 // Can add more checks if need be.
 if(!(v % 90)) members.degrees = v;
 return members.self;
 }});
}

You probably know more about the rotations than I do so I did the ones that I was 100% sure were correct. It is pretty straight forward, when the matrix object is accessed it returns a row object that then figures out what data you actually meant.

var matrix = new Matrix(2, 2);
matrix[0][1] = 12;
matrix.degrees(90);
console.log(matrix[1][0]); // => 12

Hope this helps!

answered Apr 12, 2016 at 12:42
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.