I just solved mutations and it seemed failry difficult compared to the rest of the challenges I’ve done so far. Could somebody please review my code and see If I came up with a solution that is overly complex and if so, help me with a simpler, more elegant solution? Thanks!

Yeah my return statement is a bit verbose. Other than clean looking code, why should one ‘never’ use code like that? Also, could you elaborate on the second part of your comment? Perhaps post the code you used.

I know, thank you indexOf() always returns Number so I think it doesn’t necessary to compare types.

As for your code, it works like mine with one difference: my code returns false then it meets the first char that arr[0] does not contain but your code look over all chars of arr[1]. However, it is really much better than the first variant on this page.

Very nice @kevcomedia - I used a for loop originally, and created a flag var ‘found’, but this was before I knew about ‘every’. As far as I understand it, every will exit when even one test fails, so am I correct in thinking this would be the most efficient?

My first solution is nearly the same as @dvainf’s, and many of my first solutions to the challenges used a similar approach. I only found out about every() a few days ago but never used it until now.

I’m not sure about how every() runs under the hood (like if it checks every element no matter what or immediately exits when one test fails as you mentioned), so I can’t say anything about efficiency (I’m fairly new to JS myself ).

BTW, there’s also the some() function, which returns true if at least one test passes.

EDIT. I checked out every() in the MDN and it said

The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true.

My code was almost identical to yours (although I went with true first then false, have changed that now). Thing is, the code doesn’t solve the first case - Hey vs. Hello (it’s returning true) and I can’t see why. Any ideas?

I found myself having a bit of trouble with this challenge.
I was looking at it as if there was the possibility that the first string of the array might be shorter than the second string.
I found the solutions above would return false on something such as:

mutation(["men", "women"])

but would return true on:

mutation(["women", "men"])

This is what I ended up with that would return true for both scenarios:

Hi. It’s guaranteed in the challenge that the first string is at least longer than the second. But you can still go for a more general solution.

Notice that in both branches, the code is identical except for arr[0] in the first and arr[1] in the second. You can capture these in variables called shorter and longer, then use if to set them up appropriately. You can then factor the for-loop out of the if-else and use these variables instead.

var shorter;
var longer;
// Take the chance to make the strings lowercase here.
if (arr[0].length <= arr[1].length) {
shorter = arr[0].toLowerCase();
longer = arr[1].toLowerCase();
}
else {
shorter = arr[1].toLowerCase();
longer = arr[0].toLowerCase();
}
// Now we only have one for-loop, which is nice.
for (var i = 0; i < shorter.length; i++) {
// You can also use `shorter[i]`.
// In cases like these I prefer `if (!longer.includes(shorter[i])) {`.
if (longer.indexOf(shorter.charAt(i)) < 0) {
return false; // parentheses can be omitted
}
}
return true; // you should also move this line out of the loop

Nice approach. You first removed duplicate letters then checked each letter from the second array if it matches a letter from the first. A match increments the counter, then the function returns whether the counter is the same as the second array’s length.

Now let’s examine the code more closely Let’s start with deleteCopies().tmpArr is an array that contains unique values from the arr argument. So you scan each element, then if that element is not yet in tmpArr, that element is pushed to tmpArr.

Luckily there’s a built-in function in JS that checkes whether some value is already present in an array: Array.prototype.includes(). Using this we can replace the big chunk of code in the for-loop with more concise and descriptive code:

function deleteCopies(arr) {
var tmpArr = [];
// For each item in `arr`, if that item is not included in `tmpArr`,
// push that item to `tmpArr`.
for (var i = 0; i < arr.length; i++) {
if (!tmpArr.includes(arr[i])) {
tmpArr.push(arr[i]);
}
}
// Now we have only an `if` in the for-loop and removed a bunch of variables.
return tmpArr;
}

Now let’s move to the mutation() function. Here we note that we’re basically doing the same thing we did in deleteCopies(): see if a letter from the second array is found in the first or not. Again we can use includes() to do the job.

function mutation(arr) {
// ...
// code at the beginning omitted for this snippet...
// ...
// For each item in `str2Arr`, if that item is not included in
// `str1Arr`, immediately return `false`.
for(var i = 0; i < str2Arr.length; i++){
if (!str1Arr.includes(str2Arr[i])) {
return false;
}
}
// After looking through all items in `str2Arr`, we found that
// all of its items are included in `str1Arr`, so we return `true`
// after the loop.
return true;
}

Above, if we found that a letter in str2Arr is not included in str1Arr, we immediately return false. This effectively stops the for-loop, but who cares? A letter in str2Arr is not found in str1Arr; there’s no more reason to loop through. That’s enough for us to return false right on the spot.

Now, after looping through str2Arr and we find that all of it’s letters are included in str1Arr, we can return true right after the for-loop.

Whew that’s a long post ! I’d like to say “Here’s a potato,” but this is not 9gag . Overall your’s is a good working solution. Good job ! But remember to come back to your solutions every now and then and improve them with newer things that you learned.

I felt so happy when I solved this challenge, then came here and saw how elegantly many of you fellow campers solved it. It’s fun how many ways there are to solve a problem. Here’s my, rather verbose, solution. Any suggestions for improvement much appreciated

Hi, @jvalonen! The thrill of solving a problem feels good, doesn’t it ?

Ok, let’s look at that code. The thing is that, there’s actually no need to convert the strings into arrays, because strings also have an include() function, and you can access characters like you do with arrays. You can remove the .split("") in arr1 = arr[0].toLowerCase().split("");, and your code will work fine (better, even). While you’re at it you can give arr1 and arr2 more descriptive names such as first and second, respectively.

CODE

function mutation(arr) {
// create array for characters that are present in both strings
var arr1_1 = [];
// Store lowercase versions of the string inputs.
var first = arr[0].toLowerCase();
var second = arr[1].toLowerCase();
for (var i = 0; i < second.length; i++) {
// check if `first` includes each character from `second`
if (first.includes(second[i])) {
// if `second[i]` is found in `first` push it to a new array
arr1_1.push(second[i]);
}
}
// join arr1_1 into a string
var strToCompare = arr1_1.join([separator = '']);
// compare the new string to `second`
if (second == strToCompare) {
return true;
}
return false;
}

Next, this will definitely be a source of confusion:var strToCompare = arr1_1.join([separator = '']);

Just .join(''); will do.

Finally, note this part:

if (second == strToCompare) {
return true;
}
return false;

This is a fairly common occurrence in code. It says,

If the condition is true, return true. Else (if the condition is false), return false.

But wait, if this is the case, why not just return the boolean value of the condition itself?

return second == strToCompare;

Now we have this code:

function mutation(arr) {
// create array for characters that are present in both strings.
// I could give this a more meaningful name, but naming things is hard. :)
var arr1_1 = [];
// Store lowercase versions of the string inputs.
var first = arr[0].toLowerCase();
var second = arr[1].toLowerCase();
for (var i = 0; i < second.length; i++) {
// check if `first` includes each character from `second`
if (first.includes(second[i])) {
// if `second[i]` is found in `first` push it to a new array
arr1_1.push(second[i]);
}
}
// join arr1_1 into a string
var strToCompare = arr1_1.join('');
return second == strToCompare;
}

At first I tried to solve this with a regular expression (having pretty much zero experience with those). In my head it made sense to match two sets of characters that way… I quickly hit a brick wall though.

Can a RegEx ninja chime in on why it’s not a good idea to solve this problem that way? Or if it is, how would you do it?