Get 3x3 blocks from 9x9 2d array as String

Viewed 345

I am learning Javascript and currently found myself with the following problem. I need to get each individual 3x3 block of a 9x9 2d array as a string, separated by commas.

What I mean is, for example, let's say I have the following array:

 var 2dArray = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9] ]

The result should be something like 535671192,678195342, 912348657, ... and so on, until the string is made of all the 3x3 blocks.

I thought that making nested for loops would be the best approach, but got confused along the way and I would appreciate your help.

Thank you.

4 Answers

You can use two loops to iterate over the positions of all the possible top left corners and another two loops to get all the elements in that square.

var arr = [
  [5, 3, 5, 6, 7, 8, 9, 1, 2],
  [6, 7, 1, 1, 9, 5, 3, 4, 8],
  [1, 9, 2, 3, 4, 2, 5, 6, 7],
  [8, 5, 9, 7, 6, 1, 4, 2, 3],
  [4, 2, 6, 5, 5, 3, 7, 9, 1],
  [7, 1, 3, 1, 2, 4, 8, 5, 6],
  [9, 6, 1, 5, 3, 7, 2, 8, 4],
  [2, 8, 7, 5, 1, 9, 6, 3, 5],
  [3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
for (let i = 0; i < 9; i += 3) {
  for (let j = 0; j < 9; j += 3) {
    let curr = "";
    for (let k = 0; k < 3; k++) {
      for (let l = 0; l < 3; l++) {
        curr += arr[i + k][j + l];
      }
    }
    res.push(curr);
  }
}
console.log(res);

The issue can also be solved by loops but it's good practice to solve it using the Array.map() function.

let arrayRow = "";
  const resultArray = Array2d.map((element, index) => {
     return arrayRow + element.map((element, i) => {
  return element.toString();
  });
});

you should try like this too.

var arr = [
  [5, 3, 5, 6, 7, 8, 9, 1, 2],
  [6, 7, 1, 1, 9, 5, 3, 4, 8],
  [1, 9, 2, 3, 4, 2, 5, 6, 7],
  [8, 5, 9, 7, 6, 1, 4, 2, 3],
  [4, 2, 6, 5, 5, 3, 7, 9, 1],
  [7, 1, 3, 1, 2, 4, 8, 5, 6],
  [9, 6, 1, 5, 3, 7, 2, 8, 4],
  [2, 8, 7, 5, 1, 9, 6, 3, 5],
  [3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
let i = 0,j = 0;
let justOneStr = "";
while(i < 9 && j < 9){
  justOneStr += arr[i][j];
  if(i % 3 == 2 && j % 3 == 2){
    res.push(justOneStr); 
    justOneStr="";
  }
  
  if((j % 9 == 8 || j % 3 == 2) && i % 3 != 2){
    j -= 3;
    i += 1;
  }
  else if(j % 9 == 8 && i % 3 == 2){
    j -= 9;
    i += 1;
  }
  else if(i % 3 == 2 && j % 3 == 2){
    i -= 2;
  }

  j++;
}

console.log(res);

Here's a fairly straightforward nested reduce() that returns an array of matrices of the specified size. It touches each element once, and uses the coordinates in the passed matrix to determine which sub-matrix and sub-matrix row to accumulate into.

const
  matrix = [
    [5, 3, 5, 6, 7, 8, 9, 1, 2],
    [6, 7, 1, 1, 9, 5, 3, 4, 8],
    [1, 9, 2, 3, 4, 2, 5, 6, 7],
    [8, 5, 9, 7, 6, 1, 4, 2, 3],
    [4, 2, 6, 5, 5, 3, 7, 9, 1],
    [7, 1, 3, 1, 2, 4, 8, 5, 6],
    [9, 6, 1, 5, 3, 7, 2, 8, 4],
    [2, 8, 7, 5, 1, 9, 6, 3, 5],
    [3, 4, 5, 6, 8, 6, 1, 7, 9]],

  subdivide = (matrix, width, height) => {
    return matrix.reduce((acc, row, i) => {

      row.reduce((_acc, x, j, row) => {
        const grid = Math.floor(j / width) + Math.floor(i / height) * (Math.ceil(row.length / width));
        const gridRow = i % height;
        _acc[grid] ??= [];
        (_acc[grid][gridRow] ??= []).push(x);

        return _acc;
      }, acc)

      return acc;
    }, [])
  },

  subdividedmatrix = subdivide(matrix, 3, 3);

// log submatrices
subdividedmatrix.forEach(m => console.log(JSON.stringify(m)));

// map to strings
console.log(subdividedmatrix.map(submatrix => submatrix.flat().join('')))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related