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;
}
2 Answers 2
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 []});
-
\$\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\$Douglas Gaskell– Douglas Gaskell2016年04月10日 23:55:47 +00:00Commented Apr 10, 2016 at 23:55
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!