3
\$\begingroup\$

Write a function that takes 2 inputs:

  • a matrix, for example 2-dimensional array, and
  • indices, for example [row, col]

This function should return the sum of all the second input's neighbors (up, down, left, right, diagonals).

Below is my solution. Just wanted to know if there is a better way to solve this problem. And also wanted to know if I am covering all the edge cases.

function findingNeibors(myArray, i,j) {

let rowLimit = myArray.length-1;
let columnLimit= myArray[0].length-1;
let sum = 0;

if(i<0 || j< 0) {
    console.log("invalid Index")
    return
  };

if(i>rowLimit || j> columnLimit){
    console.log("You are Out Of Bound");
    return;
}

  for(let x = Math.max(0,i-1); x<=Math.min(i+1,rowLimit); x++){
  for(let y = Math.max(0,j-1); y<=Math.min(j+1,columnLimit); y++){
    if(x!==i || y!==j){
        console.log(myArray[x][y]);
        sum+=myArray[x][y];
    }
    }
  }
  return sum;
}


let input = [
  [0,1,2,3,4],
  [1,2,3,4,5],
  [2,3,4,5,6]
]


findingNeibors(input,0,0);
findingNeibors(input,2,2,0);
findingNeibors(input,-1,3);
findingNeibors(input,3,4);

```
\$\endgroup\$
4
  • \$\begingroup\$ This is my first post. Any comments is appreciated. Thank you! \$\endgroup\$
    – RamaM
    Commented Jun 15, 2019 at 16:43
  • 4
    \$\begingroup\$ Since you ask about edge cases, I would expect that you have thought about them and have prepared some unit tests. Could you add the code of your unit tests? \$\endgroup\$
    – dfhwze
    Commented Jun 15, 2019 at 16:57
  • \$\begingroup\$ What happens if the input is not a number? Is that as intended? \$\endgroup\$
    – Mast
    Commented Jun 15, 2019 at 17:37
  • \$\begingroup\$ For edge cases i am taking care of -ve cordinates like if row/col is a -ve integer . Wanted to know if there are any other edge cases. And also if there are better ways to solve this problem as I am using nested for loops. @Mast i think the above will work for all inputs till the row/col are given as intergers. \$\endgroup\$
    – RamaM
    Commented Jun 15, 2019 at 17:38

2 Answers 2

4
\$\begingroup\$

Don't return if there is an error, throw the error.

if(i<0 || j< 0) {
    throw new Error("Invalid Index");
}

if(i>rowLimit || j> columnLimit){
    throw new Error("Index out of bounds");
}

Don't assume an array has elements

(i.e.: let columnLimit= myArray[0].length-1; will throw a TypeError if there are no elements in the list)

Play it safe.

//get first element in list, 
//if it doesn't exist set it to a default empty array
const [column = []] = myArray;
const columnLimit = column.length;

const before let and let before var

When declaring variables, always define them with const by default. You only use let when you expect that variable in question is likely to mutate. And never use var unless you have a good reason to.

Note: const arr = []; arr.push(1) mutates the array but not the variable


am I covering all the edge cases ?

Yes, you are.

Assuming that the two dimensional array has columns of equal length


Just wanted to know if there is a better way to solve this problem

There are only 8 elements max possible around a single element, and yet for every element you check to see if (i,j) != (x,y).

To solve this "problem", simply add all values (even with (i,j))

Then before returning subtract the element at (i,j)

for(let x = Math.max(0,i-1); x<=Math.min(i+1,rowLimit); x++){
  for(let y = Math.max(0,j-1); y<=Math.min(j+1,columnLimit); y++){
        sum+=myArray[x][y];
   }
 }

return sum - myArray[i][j]

Is this better? Well, it's 9 additional conditions VS an extra addition and subtraction.

\$\endgroup\$
2
  • \$\begingroup\$ for(let x = Math.max(0,i-1); x<=Math.min(i+1,rowLimit); x++){ for(let y = Math.max(0,j-1); y<=Math.min(j+1,columnLimit); y++){ sum+=myArray[x][y]; } } return sum - myArray[x][y] Thank you for all the comments. I have a question, wouldn't x and y will be undefined , as you are trying to use it outside its scope? \$\endgroup\$
    – RamaM
    Commented Jun 16, 2019 at 15:21
  • \$\begingroup\$ @mravenash that's a mistake on my part. I meant to put i,j. Usually x,y and i,j are switched around \$\endgroup\$
    – kockburn
    Commented Jun 16, 2019 at 16:39
3
\$\begingroup\$

First of all I would recommend more care formatting your code and choosing good names for your variables and functions. findingNeibors function misspells neighbors and doesn't find them, it gives a sum of all the neighbors in a matrix, so I renamed it sumMatrixNeighbors. You can see the other changes on the code below. The i and j are conventionally used for the looping iterator, so x, y seem better names for the coordinates (I am pretty sure m, n are usually used with matrix coordinates too).

The missing corner cases to check were just to validate the matrix itself and check that the coordinates were actually integers. Also the nested for loops are fine.

You should use a linter, follow a style guide and create unit tests. Some of the most important things to make good code.

function validateMatrixCoordinates(arrayMatrix, x, y) {
  if (!Array.isArray(arrayMatrix) || !Array.isArray(arrayMatrix[0])) {
    console.log("arrayMatrix is not a matrix of arrays");
    return false;
  }
  if (!Number.isInteger(x) || !Number.isInteger(y)) {
    console.log("Index is not an Integer");
    return false;
  }
  if (x < 0 || y < 0 || x > arrayMatrix.length - 1 || y > arrayMatrix[0].length - 1) {
    console.log("Index is Out Of Bounds");
    return false;
  }
  return true;
}

function sumMatrixNeighbors(arrayMatrix, x, y) {
  let rowLimit = arrayMatrix.length - 1;
  let columnLimit = arrayMatrix[0].length - 1;
  let sum = 0;

  if (!validateMatrixCoordinates(arrayMatrix, x, y)) {
    return;
  }
  for (let i = Math.max(0, x - 1); i <= Math.min(y + 1, rowLimit); i++) {
    for (let j = Math.max(0, y - 1); j <= Math.min(y + 1, columnLimit); j++) {
      if ((x !== i || y !== j) && Number.isInteger(arrayMatrix[i][j])) {
        sum += arrayMatrix[i][j];
      }
    }
  }

  return sum;
}

let input = [
  [0, 1, 2, 3, 4],
  [1, 2, 3, 4, 5],
  [2, 3, 4, 5, 6]
];

console.log('Result for [2, 1]: ' + sumMatrixNeighbors(input, 2, 1));
console.log('Result for [0, 0]: ' + sumMatrixNeighbors(input, 0, 0));
console.log('Result for ["a", 0]: ' + sumMatrixNeighbors(input, "a", 0));
console.log('Result for [1, -1]: ' + sumMatrixNeighbors(input, 1, -1));
console.log('Result for [1, 4]: ' + sumMatrixNeighbors(input, 1, 4));

\$\endgroup\$
2
  • 1
    \$\begingroup\$ The first part of your answer is good, observations about the code. Writing code to demonstrate may not be necessary, \$\endgroup\$
    – pacmaninbw
    Commented Jun 16, 2019 at 13:10
  • \$\begingroup\$ What will be the time and space complexity this?I think for time it will be O(row*cols) & space complexity - O(1). Kindly provide your thoughts. \$\endgroup\$
    – RamaM
    Commented Jun 18, 2019 at 12:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.