Basic Algorithm Scripting: Mutations - where to start

Tell us what’s happening:
I have no idea where to start with this exercise. Can anyone offer any ideas?

Your code so far


function mutation(arr) {
const newArr = arr.map(item => item.toLowerCase());
console.log(arr);
return newArr;
}

mutation(["Hello", "Hey"]);

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36.

Challenge: Mutations

Link to the challenge:

I tried the following code. It passed all the tests for true but none for false.

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2 = arr[1].toLowerCase();
  word1 = word1.split('');
  word2 = word2.split('');
  for (let i = 0; i < word2.length; i++) {
    for (let j = 0; j < word1.length; j++) {
      if (word2.indexOf(i) === word1.indexOf(j)) {
        return true;
      } else {
        return false;
      }
    } 
  } 
}

mutation(["hello", "hey"]);

Let’s break down what’s happending on this line word2.indexOf(i) === word1.indexOf(j) on the first loop through assuming an input of ['hello', 'hey'].

// word1 = ['h', 'e', 'l', 'l', 'o']
// word2 = ['h', 'e', 'y']
// i = 0, j = 0
word2.indexOf(i) === word1.indexOf(j)

// plug in the values
['h', 'e', 'y'].indexOf(0) === ['h', 'e', 'l', 'l', 'o'].indexOf(0)

// The value 0 is not equal to 'h', 'e', or 'y' so indexOf returns -1
-1 === ['h', 'e', 'l', 'l', 'o'].indexOf(0)

// The value 0 is not equal to 'h', 'e', 'l', or 'o', so indexOf returns -1
-1 === -1

// The left and right are strictly equal so the comparison evaluates to
true

So your function returns true for every test input immediately at the start of the first loop. You likely want to be using the index i to be looking at a single character of word2, like this let character = word2[i].

Hi. Return will stop the function at the first coincidence.

I suggest using this method to determine if a string contains a character: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes

It returns a boolean just like you need to do for this challenge, so it should come in handy.

const word = 'hello';
word.includes('h') // true
word.includes('e') // true
word.includes('y') // false

ok, thank you, I see what you mean.

Yes, I see. Thanks for the MDN link.

The includes method does seem very appropriate here. I’ll see what I can do with that.

thanks again

Below is my latest code. It passes everything but mutation([“hello”, “hey”]). I’m not sure if that’s random chance, or if my code is anywhere near correct.

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2 = arr[1].toLowerCase();
  word2 = word2.split('');
  for (let i = 0; i < word2.length; i++) {
    if (word1.includes(word2[i])) {
      return true;
    } else {
      return false;
    }
  }
}

mutation(["hello", "hey"]);

You’re issue is in the placement of return true. Like I did above let’s break down what happens at the if statement on the first loop through.

word1.includes(word2[i]))

// plug in values
'hello'.includes(['h', 'e', 'y'][0])

// evaluate it
'hello'.includes('h') // => true

And because that evaluates to true, the if statement immediately returns true. The issue is that you haven’t even checked ‘e’ or ‘y’ yet.

Basically, inside the loop you should immediately return false whenever a character from word2 is not found in word1. Otherwise, complete the loop and then return true after checking every character in word2.

I think I understand why my code doesn’t work but I’m not sure I understand your explanation on what to change.

Here’s my updated code, which doesn’t work either, but I’m trying to figure out what you mean by “inside the loop you should immediately return false whenever a character from word2 is not found in word1. Otherwise, complete the loop and then return true after checking every character in word2.”

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2 = arr[1].toLowerCase();
  word2 = word2.split('');
  for (let i = 0; i < word2.length;) {
    if (word1.includes(word2[i])) {
      i++;
      return false;
    } else {
      return true;
    }
  }
}

mutation(["hello", "hey"]);

@Sharad823 You are getting closer. You have 3 problems:

  1. You are only incrementing i within the if statement code block when the if statement evaluates to true. Otherwise, i never increments.
  2. You currently are returning false if a character of word2 is found in word1 instead of if a character of word 2 is not found in word1.
  3. You only want to return true once you have checked all the characters of word2. You are currently returning true or false within the first iteration of the for loop. Remember that when a return statement is executed, the function is immediately existed (regardless if a loop has completed).

Sorry, I’m not understanding. Still not clear on what’s wrong or how to fix it. Here’s another version:

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2 = arr[1].toLowerCase();
  word2 = word2.split('');
  for (let i = 0; i < word2.length; i++) {
    if (word1.includes(word2[i]) != true) {
    }  {
      return false;
    } {
      return true;
    }
  }
}

mutation(["hello", "hey"]);

You fixed the first two problems I mentioned above. Now, you just need to think about when/where you should return true. Walk through the mutation([“hello”, “hey”]) test case line by line and see if you can figure out when you return true (which is what your code is doing).

ok, thanks for the confirmation.

Can you please clarify “see if you can figure out when you return true (which is what your code is doing).”

Are you asking me to look at when the code will return true, or when it should return true? Or where in the code I should return true? And can you please explain what you mean by “(which is what your code is doing)” - what is it doing?

You can either manually go line by line with the test case and note what the values are and see when the return gets executed or you can add console.log statements before the return statements and you can see what your variables’ values are.

I’m sorry, I don’t understand what you mean by “go line by line with the test case and note what the values are and see when the return gets executed”

which values am I checking? Which return are we talking about - true or false? Both? I tried console.log(word1) and console.log(word2) but that just tells me the values assigned to those variables.

Like this (using your second rendition):

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2 = arr[1].toLowerCase();
  word2 = word2.split('');
  console.log('word1: ' + word1, 'word2: ' + word2);
  for (let i = 0; i < word2.length; i++) {
    console.log('i: ' + i, 'character: ' + word2[i]);
    if (word1.includes(word2[i])) {
      console.log(word2[i] + ' found in ' + word1);
      console.log('exiting function returning true');
      return true;
    } else {
      console.log(word2[i] + ' not found in ' + word1);
      console.log('exiting function returning false');
      return false;
    }
  }
}
1 Like

@colinthornton. I inserted the console.log statements into the code as you suggested. However I am not sure why I need to do this or what I am looking for.

This is what it logs to the console:

word1: hello word2: h,e,y
i: 0 character: h
exiting function returning false

Whatever it is, it’s a mystery to me…

Based on that logging, there a couple things that spring up in my mind.

  • the character ‘h’ is found in ‘hello’, but it returns false
  • word2 also contains the characters ‘e’, and ‘y’, but those aren’t being checked (because the function returns on the first iteration)