JavaScript Spiral Matrix Coding Challenge A whiteboarding challenge: Given a 2D array (matrix) inputMatrix of integers, create a function spiralCopy that copies inputMatrix's values into a 1D array in a clockwise spiral order. Your function then should return that array.

inputMatrix = [
  [1, 2, 3, 4, 5, 6],
  [7, 8, 9, 10, 11, 12],
  [13, 14, 15, 16, 17, 18],
  [19, 20, 21, 22, 23, 24],
  [25, 26, 27, 28, 29, 30],
  [31, 32, 33, 34, 35, 36]
]

const spiralCopy = (matrix) =&gt; {
  const spiralLength = matrix.length * matrix[0].length;
  const spiral = [];

  let iLeftRightStart = 0; // +1
  let iLeftRightEnd = matrix[0].length; // -1
  let leftRightPosition = 0; // +1
  let iTopBottomStart = 1; // +1
  let iTopBottomEnd = matrix.length; // -1
  let topBottomPosition = matrix[0].length - 1; // -1
  let iRightLeftStart = matrix[0].length - 2; // -1
  let iRightLeftEnd = 0; // +1
  let rightLeftPosition = matrix.length - 1; // -1
  let iBottomTopStart = matrix.length - 2; // -1
  let iBottomTopEnd = 1; // +1                      
  let bottomTopPosition = 0; // +1

  const leftToRight = (iStart, iEnd, position) =&gt; {
    for (let i = iStart; i &lt; iEnd; i++) {
      spiral.push(matrix[position][i]);
    }
  }

  const topToBottom = (iStart, iEnd, position) =&gt; {
    for (let i = iStart; i &lt; iEnd; i++) {
      spiral.push(matrix[i][position]);
    }
  }

  const rightToLeft = (iStart, iEnd, position) =&gt; {
    for (let i = iStart; i &gt;= iEnd; i--) {
      spiral.push(matrix[position][i]);
    }
  }

  const bottomToTop = (iStart, iEnd, position) =&gt; {
    for (let i = iStart; i &gt;= iEnd; i--) {
      spiral.push(matrix[i][position]);
    }
  }

  while (spiral.length &lt; spiralLength) {
    leftToRight(iLeftRightStart, iLeftRightEnd, leftRightPosition);
    topToBottom(iTopBottomStart, iTopBottomEnd, topBottomPosition);
    rightToLeft(iRightLeftStart, iRightLeftEnd, rightLeftPosition);
    bottomToTop(iBottomTopStart, iBottomTopEnd, bottomTopPosition);
    iLeftRightStart++;
    iLeftRightEnd--;
    leftRightPosition++;
    iTopBottomStart++;
    iTopBottomEnd--;
    topBottomPosition--;
    iRightLeftStart--;
    iRightLeftEnd++;
    rightLeftPosition--;
    iBottomTopStart--;
    iBottomTopEnd++;
    bottomTopPosition++;
  }
  return spiral;
}
console.log(spiralCopy(inputMatrix));
// prints [1, 2, 3, 4, 5, 6, 12, 18, 24, 30, 36, 35, 34, 33, 32, 31, 25, 19, 13, 7, 8, 9, 10, 11, 17, 23, 29, 28, 27, 26, 20, 14, 15, 16, 22, 21]


So the function works and runs with time complexity of O(N). However, I don't like that I'm using 12 different variables which I then increment/decrement. How can this be consolidated, and is it possible to make the algorithm even faster due to the instant access of JavaScript arrays?
Travel directions
You can imagine this problem being extended to a 3D array. That would mean you have 6 directions, which using your approach would mean half as much code again, and 4D array would have 8 directions. That would double the amount of code. This becomes impractical as you get to higher dimensions.
If you break the problem into a simpler model. Move in a direction for distance collecting items as you go then turn, every second turn decrease the distance, until zero.
A direction can be represented as a vector {x,y} that is right {1,0}, down {0,1} and so on. You store them in an array of vectors in the order you need to use.
I have solved assuming that the array given is a rhombus . You have not indicated if this is true or not. However it only requires a small modification to handle non rhombus arrays.
The result is something like
function spiral(arr) {
    var count, curDir, dist, size, x = 0, y = 0, dir = 0;
    const res = [], directions = [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x: 0, y: -1}];
    curDir = directions[0];
    dist = size = arr.length;
    count = size ** 2;
    while (count--) { 
        res.push(arr[y][x]);
        if (!--dist) {
            curDir = directions[++dir % 4];
            if (dir % 2) { size -- }
            dist = size;
        }
        x += curDir.x;
        y += curDir.y;
    }
    return res;
}

To test the function create some readable test arrays. The snippet has arrays that when processed will have values in order, so that it is easy to see if the result is correct.


[[
      [1, 2, 3, 4, 5, 6],
      [20, 21, 22, 23, 24, 7],
      [19, 32, 33, 34, 25, 8],
      [18, 31, 36, 35, 26, 9],
      [17, 30, 29, 28, 27, 10],
      [16, 15, 14, 13, 12, 101]
  ], [
      [1, 2, 3, 4, 5],
      [16, 17, 18, 19, 6],
      [15, 24, 25, 20, 7],
      [14, 23, 22, 21, 8],
      [13, 12, 11, 10, 9],
  ], [
      [1, 2, 3, 4],
      [12, 13, 14, 5],
      [11, 16, 15, 6],
      [10, 9, 8, 7],
  ], [
      [1, 2, 3],
      [8, 9, 4],
      [7, 6, 5],
  ], [
      [1, 2],
      [4, 3],
  ], [[1]]
].reverse().forEach(arr =&gt; console.log(spiral(arr).join(",")));


function spiral(arr) {
    var count, curDir, dist, size, x = 0, y = 0, dir = 0;
    const res = [], directions = [{x: 1, y: 0}, {x: 0, y: 1}, {x: -1, y: 0}, {x: 0, y: -1}];
    curDir = directions[0];
    dist = size = arr.length;
    count = size ** 2;
    while (count--) { 
        res.push(arr[y][x]);
        if (!--dist) {
            curDir = directions[++dir % 4];
            if (dir % 2) { size -- }
            dist = size;
        }
        x += curDir.x;
        y += curDir.y;
    }
    return res;
}