How to resolve the algorithm Spiral matrix step by step in the JavaScript programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Spiral matrix step by step in the JavaScript programming language

Table of Contents

Problem Statement

Produce a spiral array.

A   spiral array   is a square arrangement of the first   N2   natural numbers,   where the numbers increase sequentially as you go around the edges of the array spiraling inwards.

For example, given   5,   produce this array:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Spiral matrix step by step in the JavaScript programming language

Spiral Array

First Approach

The first approach to creating a spiral array is a bit more complex. It uses a combination of loops and conditional statements to build the array.

spiralArray = function (edge) {
   var arr = Array(edge),
       x = 0, y = edge,
       total = edge * edge--,
       dx = 1, dy = 0,
       i = 0, j = 0;
   while (y) arr[--y] = [];
   while (i < total) {
       arr[y][x] = i++;
       x += dx; y += dy;
       if (++j == edge) {
           if (dy < 0) {x++; y++; edge -= 2}
           j = dx; dx = -dy; dy = j; j = 0;
      }
   }
   return arr;
}

Implementation Details:

  • The code initializes an array arr of size edge, representing the spiral array.
  • It sets initial positions for x and y and initializes variables for tracking the number of elements (total), the direction changes (dx and dy), and the current index (i and j).
  • It iterates to initialize rows in the arr array.
  • The main loop runs until all elements are filled in the spiral.
  • It assigns the current index i to the current position in arr and increments i.
  • It moves in the current direction and updates x and y accordingly.
  • It checks if the current row has been completed (j == edge). If so, it adjusts the direction and movement based on the current position in the spiral.
  • It returns the completed arr array.

Second Approach

The second approach uses a recursive function to generate the spiral array. It rotates the spiral by 90 degrees clockwise with each recursive call.

(function (n) {

 // Spiral: the first row plus a smaller spiral rotated 90 degrees clockwise
 function spiral(lngRows, lngCols, nStart) {
   return lngRows ? [range(nStart, (nStart + lngCols) - 1)].concat(
     transpose(
       spiral(lngCols, lngRows - 1, nStart + lngCols)
     ).map(reverse)
   ) : [
     []
   ];
 }

 // rows and columns transposed (for 90 degree rotation)
 function transpose(lst) {
   return lst.length > 1 ? lst[0].map(function (_, col) {
     return lst.map(function (row) {
       return row[col];
     });
   }) : lst;
 }

 // elements in reverse order (for 90 degree rotation)
 function reverse(lst) {
   return lst.length > 1 ? lst.reduceRight(function (acc, x) {
     return acc.concat(x);
   }, []) : lst;
 }

 // [m..n]
 function range(m, n) {
   return Array.apply(null, Array(n - m + 1)).map(function (x, i) {
     return m + i;
   });
 }

})(5);

Implementation Details:

  • The code defines a recursive function spiral that takes three parameters: lngRows (length of rows), lngCols (length of columns), and nStart (starting index).
  • The range function creates a range of numbers [m, n].
  • The transpose function transposes rows and columns for 90-degree rotation.
  • The reverse function reverses the order of elements for 90-degree rotation.
  • The spiral function generates the first row and concatenates it with the transposed and reversed smaller spiral generated by the recursive call.
  • It recursively rotates the spiral by 90 degrees until the desired size is reached.

Third Approach

The third approach uses a different approach to generate the spiral array. It maintains two queues, one for the current row and one for the next row, and iteratively fills the array.

(() => {
   "use strict";

   // ------------------ SPIRAL MATRIX ------------------

   // spiral :: Int -> [[Int]]
   const spiral = n => {
       const go = (rows, cols, start) =>
           Boolean(rows) ? [
               enumFromTo(start)(start + pred(cols)),
               ...transpose(
                   go(
                       cols,
                       pred(rows),
                       start + cols
                   )
               ).map(reverse)
           ] : [
               []
           ];

       return go(n, n, 0);
   };


   // ---------------------- TEST -----------------------
   // main :: () -> String
   const main = () => {
       const
           n = 5,
           cellWidth = 1 + `${pred(n ** 2)}`.length;

       return unlines(
           spiral(n).map(
               row => (
                   row.map(x => `${x}`
                   .padStart(cellWidth, " "))
               )
               .join("")
           )
       );
   };


   // --------------------- GENERIC ---------------------

   // enumFromTo :: Int -> Int -> [Int]
   const enumFromTo = m =>
       n => Array.from({
           length: 1 + n - m
       }, (_, i) => m + i);


   // pred :: Enum a => a -> a
   const pred = x => x - 1;


   // reverse :: [a] -> [a]
   const reverse = xs =>
       "string" === typeof xs ? (
           xs.split("").reverse()
           .join("")
       ) : xs.slice(0).reverse();


   // transpose :: [[a]] -> [[a]]
   const transpose = rows =>
       // The columns of the input transposed
       // into new rows.
       // Simpler version of transpose, assuming input
       // rows of even length.
       Boolean(rows.length) ? rows[0].map(
           (_, i) => rows.flatMap(
               v => v[i]
           )
       ) : [];


   // unlines :: [String] -> String
   const unlines = xs =>
       // A single string formed by the intercalation
       // of a list of strings with the newline character.
       xs.join("\n");


   // MAIN ---
   return main();
})();

Implementation Details:

  • The code defines a recursive function spiral that takes three parameters: rows, cols, and start.
  • The enumFromTo function creates a range of numbers [m, n].
  • The pred function subtracts 1 from a given number.
  • The reverse function reverses the order of elements.
  • The transpose function transposes rows and columns.
  • The unlines function joins a list of strings into a single string with newline characters.
  • The main function generates the spiral array and formats it for output.

Source code in the javascript programming language

spiralArray = function (edge) {
    var arr = Array(edge),
        x = 0, y = edge,
        total = edge * edge--,
        dx = 1, dy = 0,
        i = 0, j = 0;
    while (y) arr[--y] = [];
    while (i < total) {
        arr[y][x] = i++;
        x += dx; y += dy;
        if (++j == edge) {
            if (dy < 0) {x++; y++; edge -= 2}
            j = dx; dx = -dy; dy = j; j = 0;
       }
    }
    return arr;
}

// T E S T:
arr = spiralArray(edge = 5);
for (y= 0; y < edge; y++) console.log(arr[y].join(" "));


(function (n) {

  // Spiral: the first row plus a smaller spiral rotated 90 degrees clockwise
  function spiral(lngRows, lngCols, nStart) {
    return lngRows ? [range(nStart, (nStart + lngCols) - 1)].concat(
      transpose(
        spiral(lngCols, lngRows - 1, nStart + lngCols)
      ).map(reverse)
    ) : [
      []
    ];
  }

  // rows and columns transposed (for 90 degree rotation)
  function transpose(lst) {
    return lst.length > 1 ? lst[0].map(function (_, col) {
      return lst.map(function (row) {
        return row[col];
      });
    }) : lst;
  }

  // elements in reverse order (for 90 degree rotation)
  function reverse(lst) {
    return lst.length > 1 ? lst.reduceRight(function (acc, x) {
      return acc.concat(x);
    }, []) : lst;
  }

  // [m..n]
  function range(m, n) {
    return Array.apply(null, Array(n - m + 1)).map(function (x, i) {
      return m + i;
    });
  }

  // TESTING
  
  var lstSpiral = spiral(n, n, 0);


  // OUTPUT FORMATTING - JSON and wikiTable
  function wikiTable(lstRows, blnHeaderRow, strStyle) {
    return '{| class="wikitable" ' + (
      strStyle ? 'style="' + strStyle + '"' : ''
    ) + lstRows.map(function (lstRow, iRow) {
      var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');

      return '\n|-\n' + strDelim + ' ' + lstRow.map(function (v) {
        return typeof v === 'undefined' ? ' ' : v;
      }).join(' ' + strDelim + strDelim + ' ');
    }).join('') + '\n|}';
  }

  return [
    wikiTable(

      lstSpiral,

      false,
      'text-align:center;width:12em;height:12em;table-layout:fixed;'
    ),
    
    JSON.stringify(lstSpiral)
  ].join('\n\n');

})(5);


[[0,1,2,3,4],[15,16,17,18,5],[14,23,24,19,6],[13,22,21,20,7],[12,11,10,9,8]]


(() => {
    "use strict";

    // ------------------ SPIRAL MATRIX ------------------

    // spiral :: Int -> [[Int]]
    const spiral = n => {
        const go = (rows, cols, start) =>
            Boolean(rows) ? [
                enumFromTo(start)(start + pred(cols)),
                ...transpose(
                    go(
                        cols,
                        pred(rows),
                        start + cols
                    )
                ).map(reverse)
            ] : [
                []
            ];

        return go(n, n, 0);
    };


    // ---------------------- TEST -----------------------
    // main :: () -> String
    const main = () => {
        const
            n = 5,
            cellWidth = 1 + `${pred(n ** 2)}`.length;

        return unlines(
            spiral(n).map(
                row => (
                    row.map(x => `${x}`
                    .padStart(cellWidth, " "))
                )
                .join("")
            )
        );
    };


    // --------------------- GENERIC ---------------------

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = m =>
        n => Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);


    // pred :: Enum a => a -> a
    const pred = x => x - 1;


    // reverse :: [a] -> [a]
    const reverse = xs =>
        "string" === typeof xs ? (
            xs.split("").reverse()
            .join("")
        ) : xs.slice(0).reverse();


    // transpose :: [[a]] -> [[a]]
    const transpose = rows =>
        // The columns of the input transposed
        // into new rows.
        // Simpler version of transpose, assuming input
        // rows of even length.
        Boolean(rows.length) ? rows[0].map(
            (_, i) => rows.flatMap(
                v => v[i]
            )
        ) : [];


    // unlines :: [String] -> String
    const unlines = xs =>
        // A single string formed by the intercalation
        // of a list of strings with the newline character.
        xs.join("\n");


    // MAIN ---
    return main();
})();


  

You may also check:How to resolve the algorithm Polynomial long division step by step in the D programming language
You may also check:How to resolve the algorithm Array length step by step in the Avail programming language
You may also check:How to resolve the algorithm Convert seconds to compound duration step by step in the Phix programming language
You may also check:How to resolve the algorithm Find the intersection of a line with a plane step by step in the Racket programming language
You may also check:How to resolve the algorithm Strip comments from a string step by step in the Factor programming language