How to extract elements of a matrix in a particular pattern using javascript?

Viewed 199

How to extract elements of a matrix in a particular pattern using javascript?

following is the code for generating a 2d matrix of size any

var matrix = [];
for(var i=0; I<size; i++) {
    matrix[i] = [];
    for(var j=0; j<size; j++) {
        matrix[i][j] = undefined;
    }
}

enter image description here

so the first one is the original matrix. second one is the matrix made out by removing some elements/ cells.

// don't worry about splicing... this is just a demo.
[[3,5], [4,5], [4,2] ... ].forEach(([i,j], _, arr) => delete arr[i][j])

***** This is where you begin *****

(from the above splices matrix the following has to be done)

so what I want to achieve is that I want to separate or group cells from the above spliced matrix in the following manner. (like concentric circles/squares fashion by keeping in mind the fact that some cells are removed)

enter image description here

first you start at the central element [i,j], then move to the next level 3 x 3 & assign a value to all concentric cells (or separate cell address out)... then move to the next level 4 x 4 assign a value to all concentric cells (or separate cell address out) and so on...

Note that the spliced matrix is the starting point

travel in this fashion outwards (like concentric squares):

enter image description here

the idea is that:\

  1. generate a matrix of size n * n.
  2. remove some elements (that will be any)

... from here the algorithm starts...

  1. separate cells from the above splices matrix in a concentric square fashion. --> this is where I want help (step 3 only)

In simple terms I want to separate out the cells from the matrix in the following order (one level at a time 3 x 3 first then 4 x 4 then 5 x 5 and so on.... ( from the above spliced matrix, which means that some cells will be already removed.)

enter image description here

keep in mind the fact that some cells are already removed (so you'll have to skip them -)

3 Answers

First, figure out the centroid of the square. The center is going to be at {length / 2, width / 2}. We're dealing in integer units, so floor. Using the convention that the top left of the figure is {0, 0} , then ie a 7x7 square has its center at

{floor(7/2), floor(7/2)} === {3,3}

Then, figure out a distance formula. In the pictures, the unit squares in purple are all the squares where either the x coordinate or y coordinate are N units away from the center. In other words

max(x - centerX, y-centerY) === N

I agree with @audzzy, you don't want to delete anything since that actually changes the length of an individual row, which we don't want. Instead just set it to another value.

So the idea is to:

  1. find the center
  2. iterate over each unit square
  3. clear any unit squares which are N distance from the center
const clearCircle = (mat, N) => {
    // find the center
    const maxI = mat.length, maxJ = mat[0].length,
        center = {
            i: Math.floor(mat.length / 2),
            j: Math.floor(mat[0].length / 2)
        };
    // iterate over all units
    for (let i = 0; i < maxI; i++) {
        for (let j = 0; j < maxJ; j++) {
            // check if its N units from the center
            if (Math.max(Math.abs(center.i - i), Math.abs(center.j - j)) === N) {
                mat[i][j] = "   ";
            }
        }
    }
    return mat;
}

Full example:

/*jshint esnext: true */
const generateMat = size => {
    const mat = [];
    for (let i = 0; i < size; i++) {
        mat[i] = [];
        for (let j = 0; j < size; j++) {
            mat[i][j] = "[ ]";
        }
    }
    return mat;
}

const mat = generateMat(9);

const logMat = mat => console.log("\n" + mat.map(row => (row).join(" ")).join("\n") + "\n");

const clearCircle = (mat, N) => {
    // find the center
    const maxI = mat.length, maxJ = mat[0].length,
        center = {
            i: Math.floor(mat.length / 2),
            j: Math.floor(mat[0].length / 2)
        };
    // iterate over all units
    for (let i = 0; i < maxI; i++) {
        for (let j = 0; j < maxJ; j++) {
            // check if its N units from the center
            if (Math.max(Math.abs(center.i - i), Math.abs(center.j - j)) === N) {
                mat[i][j] = "   ";
            }
        }
    }
    return mat;
}


logMat(mat);
logMat(clearCircle(mat, 1));
logMat(clearCircle(mat, 2));
logMat(clearCircle(mat, 3));

Well... you just need exclude squares outside boundaries, after that you can just select elements which are in the most external layer of the matrix!

Something like that:

function extractElements(layer, matrix) {
  const elements = []
  const n = matrix.length; // matrix NxN
  const frontIndex = layer -1;
  const backIndex = n - layer;
  
  if(layer <= 0 || layer > Math.ceil(n/2)) {
    console.log("invalid layer");
    return [];
  }

  for(let i = 0; i < n; ++i){
    if(i < frontIndex || i > backIndex)
        continue;
        
    for(let j = 0; j < n; ++j){
      if(j < frontIndex || j > backIndex)
        continue;
        
      if(i === frontIndex || i === backIndex || j === frontIndex || j === backIndex) {
        if(matrix[i][j] !== undefined)
          elements.push(matrix[i][j]);
      }
    } 
  }
  return elements;
}

So, if you want the most external layer of a matrix 5x5, you can call extractElements(1, matrix)

Good code!

here's some basic code to do what you want (here I colored the cells, you could add them to a result array, or do whateve else you want)

notice it has very little iterations- only goes over the "wanted" cells every time- and colors the relevant lines and columns,

(for visual reasons - '-' is a regular cell, ' ' is deleted cell, 'a' is a "purple" cell)

setMatrix is basically the interesting part that gets the interesting cells of every level..

let setMatrix = (matrix, level, value) => {
  let size = matrix.length; 
  for(let x=Math.floor(size/2)-level;x<=Math.floor(size/2)+level;x++){
    matrix[x][Math.floor(size/2)-level] = matrix[x][Math.floor(size/2)-level] == ' ' ? ' ' : value;
    matrix[x][Math.floor(size/2)+level] = matrix[x][Math.floor(size/2)+level] == ' ' ? ' ' : value;
  
    if(x!=Math.floor(size/2)-level && x!=Math.floor(size/2)+level){
      matrix[Math.floor(size/2)-level][x] = matrix[Math.floor(size/2)-level][x] == ' ' ? ' ' : value;
      matrix[Math.floor(size/2)+level][x] = matrix[Math.floor(size/2)+level][x] == ' ' ? ' ' : value;
    }
  }
}

and here's some code to call it for each level:

function doWork(){
  // init
  let size = 7;
  var matrix = [];
  for(var i=0; i<size; i++) {
      matrix[i] = [];
      for(var j=0; j<size; j++) {
          matrix[i][j] = '-';
      }
  }
  
  // delete
  [[1,1], [2,3], [2,5], [5,1], [6,4]].forEach(([i,j])=> matrix[i][j] = ' ');

  // go over each level
  for(let i=0;i<=Math.floor(size/2);i++){
    // set
    setMatrix(matrix, i, 'a');

    // print
    for(let x=0;x<size;x++){
      let line='';
      for(let y=0;y<size;y++){
        line+=matrix[x][y];
      }
      console.log(line);
    }
    console.log();
    
    //reset
    setMatrix(matrix, i, '-');
  }
} 

doWork();
Related