6

I am doing an algorithm challenge for practice in JS. I have a program that runs through a loop, and when the condition is met, the function should return false. However, when the condition is met, the return doesn't work and the function always ends up returning true.

const isDiagonalLeftWristband = (band) => {
  band.forEach((row, y) => {
    row.forEach((item, x) => {
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++) {        
        if (band[y][x] !== band[y+i][x+i]) {
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        }
      }
    })
  })
  return true;
}


const band3 = [
  ["A", "B", "C"],
  ["C", "Z", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

Output:

false //from console log
false //from console log
true //from function return statement

Any help would be greatly appreciated!

2 Answers 2

3

The return false will only exit the (item, x) => {} anonymous function and not the isDiagonalLeftWristband() as you expect. After the two forEach are executed isDiagonalLeftWristband() will always return true on the end. You can use loops to avoid this problem.

const isDiagonalLeftWristband = (band) => {
  for (let [y, row] of band.entries()) {
    for (let [x, item] of row.entries()) {
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++) {        
        if (band[y][x] !== band[y+i][x+i]) {
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        }
      }
    }
  }
  return true;
}

const band3 = [
  ["A", "B", "C"],
  ["C", "Z", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

forEach is not designed to terminate early. It will always iterate over all the elements. (it's in the name :)). From the MDN documentation:

There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.

Early termination may be accomplished with:

A simple for loop
A for...of / for...in loops
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()

Array methods: every(), some(), find(), and findIndex() test the array elements with a predicate returning a truthy value to determine if further iteration is required.

You can instead use one of the suggested functions designed to test the elements of an array with a predicate. every() tests if all elements of an array pass some test; which is, at least semantically, what you need.

const isDiagonalLeftWristband = (band) => {
  return band.every((row, y) => {
    return row.every((item, x) => {
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++) {        
        if (band[y][x] !== band[y+i][x+i]) {
          return false;
        }
      }
      return true;    
     });
  });
}

const band3 = [
  ["A", "B", "C"],
  ["C", "B", "B"],
  ["B", "C", "A"],
  ["A", "B", "C"]
];

console.log(isDiagonalLeftWristband(band3))

Sign up to request clarification or add additional context in comments.

2 Comments

This has solved my problem, but for the sake of learning, is there a way to make the function work with forEach? Naoufal's answer is a possible solution, but like he pointed out, his solution won't exit after finding the first false.
@NicholasNewman I've edited my answer to answer your question. In short, there is no sensible way to terminate a forEach early.
0

the return false; statments only return the value to the function it belongs to, which is

(item, x) => {
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++) {        
        if (band[y][x] !== band[y+i][x+i]) {
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          return false;
        }
      }
    }

your code must work in a way that it can return the false to the main function, you can use this approach:

const isDiagonalLeftWristband = (band) => {
  let returnValue = true;
  band.forEach((row, y) => {
    row.forEach((item, x) => {
      for(let i = 0; (i < band[y].length - x) && (i < band.length - y); i++) {        
        if (band[y][x] !== band[y+i][x+i]) {
          console.log(false) //FALSE GETS OUTPUTTED MULTIPLE TIMES
          returnValue = false;
          // return false;
        }
      }
    })
  })
  return returnValue;
}

What domondo suggested is way better because the function exists once it finds the first false

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.