Last active
August 2, 2017 17:53
-
-
Save AaronO/eb430ad7170142b13bad7548f9bcbe12 to your computer and use it in GitHub Desktop.
Turn a 2d matrix into a flat array, of values in "clockwise order"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//// | |
// Example (square) matrices | |
//// | |
// 1x1 | |
const M1 = [ | |
[ 4 ], | |
]; | |
const M2 = [ | |
[1, 2], | |
[3, 4], | |
]; | |
const M3 = [ | |
[1, 2, 3], | |
[4, 5, 6], | |
[7, 8, 9], | |
]; | |
const M4 = [ | |
[1, 2, 3, 4], | |
[5, 6, 7, 8], | |
[9, 10, 11, 12], | |
[13, 14, 15, 16], | |
]; | |
// Utility functions | |
function empty(arr) { return arr.length === 0; } | |
function first(arr) { return arr[0]; } | |
function middle(arr) { return arr.slice(1, arr.length - 1); } | |
function last(arr) { return arr[arr.length - 1]; } | |
function reverse(arr) { return arr.slice().reverse(); } // Return a reversed copy of an array (don't modify in place) | |
// Returns a 2d matrix inside a given 2d matrix by "stripping" the outer numbers | |
function MatrixMiddleNumbers(matrix) { | |
// Only keep the middle rows | |
return middle(matrix) | |
// Only keep the middle elements of the middle rows | |
.map(row => middle(row)); | |
} | |
// Get the numbers on the outer edges of a 2d matrix (in clockwise order) | |
function MatrixOuterNumbers(matrix) { | |
const firstRow = first(matrix); | |
const middleRows = middle(matrix); | |
const lastRow = last(matrix); | |
// Edge case: if only one row in matrix, then just return that (because it's already in clockwise order) | |
if (matrix.length === 1) { | |
return firstRow; | |
} | |
return [] | |
// All of first row | |
.concat(firstRow) | |
// Last elements of middle rows | |
.concat(middleRows.map(last)) | |
// Last row (in reverse order) | |
.concat(reverse(lastRow)) | |
// First elements of middle rows in reverse order | |
.concat(reverse(middleRows).map(first)); | |
} | |
function MatrixToSpiralRecursive(matrix) { | |
// Stop recursing when matrix is empty (no rows left) | |
if (empty(matrix)) { | |
return []; | |
} | |
// Get outer numbers | |
const spiral = MatrixOuterNumbers(matrix); | |
// Get "sub" matrix | |
const subMatrix = MatrixMiddleNumbers(matrix); | |
// Recurse a run this same function on the smaller matrix | |
return spiral.concat(MatrixToSpiralRecursive(subMatrix)); | |
} | |
function MatrixToSpiralImperative(matrix) { | |
// Get matrix's dimensions | |
const X = matrix[0].length; | |
const Y = matrix.length; | |
// Results | |
let result = []; | |
// Our starting x, y coordinates | |
let x = 0; | |
let y = 0; | |
// Our starting directions | |
let dx = 1; | |
let dy = 0; | |
// Number of remaining steps in each direction | |
let steps = 0; | |
let xRemaining = X; | |
let yRemaining = Y-1; | |
// Loop ! | |
for (let i = 0; i < X*Y; i++) { | |
// Add current element | |
result.push(matrix[y][x]); | |
// Increase the number of steps we've advanced in the current direction | |
steps++; | |
// Change direction when we hit the remaining number of steps in the direction we're going | |
// Changing direction after going X | |
if (dx !== 0 && steps >= xRemaining) { | |
dy = dx; | |
dx = 0; | |
// Reset number of steps (since we're going in a new direction) | |
steps = 0; | |
xRemaining--; | |
} else if (dy !== 0 && steps >= yRemaining) { | |
// Changing direction after going Y | |
dx = -dy; | |
dy = 0; | |
steps = 0; | |
yRemaining--; | |
} | |
// Move forward given current direction | |
x += dx; | |
y += dy; | |
} | |
return result; | |
} | |
// Utility check function | |
function arrEquals(a1,a2) { return JSON.stringify(a1)==JSON.stringify(a2); } // Dirty but good enough for what we need | |
// Run tests | |
console.log('M1:', MatrixToSpiralImperative(M1)); | |
console.log('M2:', MatrixToSpiralImperative(M2)); | |
console.log('M3:', MatrixToSpiralImperative(M3)); | |
console.log('M4:', MatrixToSpiralImperative(M4)); | |
console.log(arrEquals(MatrixToSpiralImperative(M1), MatrixToSpiralRecursive(M1))); | |
console.log(arrEquals(MatrixToSpiralImperative(M2), MatrixToSpiralRecursive(M2))); | |
console.log(arrEquals(MatrixToSpiralImperative(M3), MatrixToSpiralRecursive(M3))); | |
console.log(arrEquals(MatrixToSpiralImperative(M4), MatrixToSpiralRecursive(M4))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment