Mutations: why do we need indexOf? Can we use includes()?

Hi there - I’m struggling with the mutations exercise. I ended up looking at the answers but i do not understand at all why the use of “indexOf()”. I thought using “.includes()” would be more appropriate. I guess it isn’t as it is not working for me.
Additionally, i thought using ‘split()’ was necessary to be able to look through each letter instead of the actual word… i see it’s feasible to avoid ‘split’ …
We are supposed to find the letters in 'arr[1] ’ in 'arr[0]. The order shouldn’t matter.

Here’s my code which does not work… any guidance?

Thanks much!
Describe your issue in detail here.

   **Your code so far**
function mutation(arr) {
 var splitArr0 = arr[0].toLowerCase().split('');
 var splitArr1 = arr[1].toLowerCase().split('');
 console.log(splitArr0);
 console.log(splitArr1);

 for(var i=0; i<splitArr0.length; i++){
   for (var j=0; j<splitArr1.length; j++){
     return splitArr0[i].includes(splitArr1[j]);
   }
 }
}

console.log(mutation(["Hello", "hello"]));
   **Your browser information:**

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

Challenge: Mutations

Link to the challenge:

You are returning immediately in you second loop which is ending the entire function. The code you’ve written simply returns a boolean of wether the first letter in the second word exist in the first word which is not what you want.

1 Like

Why wasn’t includes used? That was part of ES2015 - it may not have been common when it was written.

I was able to get this to work with includes but I had to rethink some of your logic. As caryaharper says, there is a problem with that logic. In addition to that, I had a problem with your looping. Do you really need to index through the first string or do you just need to see if it is there.

Fixing the logic problem and cutting down to 1 loop, I was able to get this to pass with includes.

3 Likes

Thank you. So if I understand you correctly.

  1. I should not return in my second loop , and just return after the for loop. Is that correct?

  2. I do not need to create a loop for arr[0] but just arr[1]. right? Forgive me, maybe i’ve just been spending too much time on this and need a break, but wouldn’t i need to go through each letter in arr[0] to compare?

I would recommend using a bit of memory to increase performance in time.

You can loop through the first string once saving wether you’ve seen a letter or not in an object, and then you can loop through the second string checking against this object.

thank you. I’m trying with one loop now…

Don’t get frustrated, this is hard stuff when you’re learning it. We all went through this.

1 Like

Thank you so much! I always need to remember that.

I tried with one loop. Still doesn’t pass all tests but most of them… Can you spot the error?

function mutation(arr) {
var finalAnswer;
var splitArr0 = arr[0].toLowerCase().split('');
  var splitArr1 = arr[1].toLowerCase().split('');
  console.log(splitArr0);
  console.log(splitArr1);
  for(var i=0; i<splitArr1.length; i++){
    finalAnswer = splitArr0.includes(splitArr1[i]);
   // return splitArr0.includes(splitArr1[i]);//why can't i just return this....
  }
  return finalAnswer;
}
console.log(mutation(["Hello", "hello"]));

thanks so much!

1 Like

If the last letter in string2 exist in string1 then finalAnswer will be set to true.

This is similar to having written:

function mutation(arr) {
   var splitArr0 = arr[0].toLowerCase().split('');
   var splitArr1 = arr[1].toLowerCase().split('');
   return  splitArr0.includes(splitArr1[splitArr1.length - 1])
}
1 Like

Right. Once you find a letter that isn’t in there, do you need to check the rest? I think you’re going to have two return statements. One to leave immediately once you realize there is not a match, the other if you don’t find any problems.

2 Likes

thanks a million. I always get confused with “return.” I don’t know why i always think i should use it only once. Thanks so much!

Also if you are ever wondering what certain JavaScript things do I highly recommend checking:

This is a great source of documentation.

1 Like

Kevin - thanks so much !! I was able to finally solve the exercise with your help and everyone here who shared their guidance!
As i was thinking more about this exercise, I am not 100% sure I understand the difference with having two returns and having a variable that will get assigned a couple of answers based on an if/else clause and then just call that variable.

With two returns:

  for(var i=0; i<splitArr1.length; i++){
    if(splitArr0.includes(splitArr1[i])== false){
      return false;
    }
  }
  return true;

returning a variable

  for(var i=0; i<splitArr1.length; i++){
    if(splitArr0.includes(splitArr1[i])== false){
      finalAnswer= false;
    }
    else {
    finalAnswer = true;
  }
  return finalAnswer;

below is the full exercise, which has now passed all tests

function mutation(arr) {
var finalAnswer;
var splitArr0 = arr[0].toLowerCase().split('');
 var splitArr1 = arr[1].toLowerCase().split('');
  for(var i=0; i<splitArr1.length; i++){
    if(splitArr0.includes(splitArr1[i])== false){
      return false;
    }
  }
  return true;
}
console.log(mutation(["Hello", "hello"]));

Practically, unless you are dealing with a very very large array, there is little difference. But we are programmers and thus tend to obsess over these things :slight_smile:

Some advantages of the two return method:

  • You don’t need to create an extra variable to hold the answer so the code is a little cleaner (and uses just slightly less memory).
  • As soon as you hit the first false you can exit the function, which means you don’t have to go through the remainder of the array wasting unnecessary CPU cycles.

In general I think programmers like to be as concise as possible (while still being easy to read), so the two return method is probably the most popular way to do this.

P.S. If you want to be really picky and obsessive then you should use === instead of == for the comparison. Actually, most programmers would just use ! at the beginning.

1 Like

In a way, this isn’t a bad instinct. One thing that has historically been taught as “clean” code is for functions to have a “single entrance, single exit”. The strictness of this relates more to older paradigms where you would exit a loop without returning. It’s still a good idea not to have return statements all over the place but an “early exit” like this is a common optimization technique.

4 Likes

Sure, you can do that one return version, I would just want to break out of it once I found my false case. I still think the double return better, I think it’s cleaner and it’s more clear that you are bailing on that function as soon as the false case is detected, not sething a flag to do it later, disconnecting cause and effect.

Ariel is right about the old notion “one entry, one exit”. I’m old enough to remember bring taught that. I always thought of it as a holdover from older languages that used a lot of goto statements so it was really easy to create spaghetti code. Nowadays, it is not as big of a thing and in some cases encouraged, like in a return early pattern, which I use a lot.

The issue nowadays (afaict) is readability and maintainability. I think that as long as you keep your functions small, judicious use of returns can improve both.

2 Likes

Thanks everyone for your guidance. I truly appreciate it and value it.

Thanks about the notion of applying a break after return and for all your guidance!

Thank you so much!!! Very very helpful!!

Thanks for the guidance. Truly appreciate it!