Look at my (preliminary) logic for missing letters

Tell us what’s happening:
I’m sketching ideas now and thinking about my general approach before I consider methods or loops or whatever. Below I have my gameplan. I’d like to know if some of the things I’m thinking of are actually possible with Javascript in the way I want to use them. If not, then critiquing my logic would be greatly appreciated.

Thank you

Your code so far



fearNotLetter("abce");
//1.  Convert str elements to ASCII
//2.   Find gap(s) in numerical sequence of ASCII
//3.   Convert this gap into a string element
//4. Return this string element

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/missing-letters/

you can, you will have to do some Read-Search-Ask as the methods you need are not all taught here in FCC, but it is something you can absolutely do

Yep, that looks sensible — you’ll want to look at charCodeAt() and String.fromCharCode for steps 1 and 3 repectively. You don’t need to convert them all up front either, you can do a loop through the string, peeking at the next character every time

The logic is good so something is wrong in my syntax. It goes wrong somewhere in my reduce code. Where am I messing up there? I can’t find anything. It seems like I’m using the reduce function correctly, although I am weakest on this particular method and feel highly uncomfortable with it for some reason).


function fearNotLetter(str) {
  //Create variables for containers for initial conversion of str to ASCII and retrieval of missing number
  var nums = [];
  var missingNum = [];
  //Loop through str to convert all elements to their ASCII form and push to first empty container
  for(var i = 0; i < str.length; i++){
    if(i < str.length){
 nums.push(str.charCodeAt(i))}
  }
  //Use reduce method to determine missing number by determining which interval of numbers contains a difference greater than 1.  Add 1 to lesser number to determine missing number and use fromCharCode to convert ASCII form to string form
 nums = nums.reduce((prev, curr)=>{
   if(curr - prev > 1){
     missingNum.push(fromCharCode(prev + 1))
   }
 })
 



      
   
   
  return missingNum;

}
fearNotLetter("abce");

console.log(curr, prev) inside your function.

Can I suggest that next time you try to explain the logic and syntax of your code to someone that doesn’t know your goal?

What determines the value of prev in the reduce method?

This isn’t how the reduce function is used. reduce takes an array of things of type A and turns it into a single value B, using the callback function to go through the array and sequentially merging each value into B.

It’s not a version of a loop, which is what you’re trying to use it for.

And you don’t need reduce here, it’s not the right tool: you have a loop, you can check the next value in the string in that loop. And you don’t need to convert up front, it’s just extra work you’re making for yourself. You only need to know what the missing letter is, once you’ve found it, the rest of the string is irrelevant

hey bananahair
Here you have code duplication :nerd: :

for(var i = 0; i < str.length; i++){
    if(i < str.length){
 nums.push(str.charCodeAt(i))}
  }

And about return - you have to return only first letter which is missed – you don’t need reduce() to do this :coffee:


//It's not passing, but I didn't expect it to.  I'm at an impasse and would like a little help.

function fearNotLetter(str) {
  var newLetter;
  //So if I only focus on one string element at a time I don't have to convert everything ASCII form.  Therefore, per the advice above I'm using a loop and an if statement to test each str element to see if it does not exist within the necessary interval specified in the challenge
  for(var i = 0; i < str.length; i++){
    if(str[i] !== /[a-e]/){
     newLetter = str.charCodeAt(this[i]);
    }
console.log(newLetter);
/*I have some issue with my code above that I'm not sure how to address and would seek your advice.  
1. My regex is not universal and, therefore, would pass no other test except the particular one I'm addressing.  Is regex appropriate to use here?  I think there might be general expressions for addressing an interval (maybe /^\w*$/), but if it's simply a bad idea then I can move on and try to think of something else
2. Do I need to assign my fromCharCode() conversion to a variable?  I did this for the purpose of checking it and I'm not sure if I want to mutate str in case I might need it in the code?  I don't know what I would need it for and I feel that my fear might be illogical.  So confirmation of its illogical nature means I could make things a bit simpler
3. Is it necessary to use this?  Perhaps my if statement is specific enough that I could just use i as long as I kept it within the scope of the if statement?

Much obliged for your guidance in this matter.
*/

  }
  return newLetter;
}

fearNotLetter("abce");

Right, so you have a loop, and what you want to know is if the letter after the current one is the next one. You don’t need to use a regex, you just need to know what the character codes are

How could str[i] be not equal to a letter in the range a-e if the string is “abce” and the letters are all in that range? How can this help you in determining if there is a gap?

You need to confront each letter in the string with the following one, (or the previous one, the choice is yours) to see if they are consecutive or not.

1 Like

Okay, I sought a video tutorial and I was able to complete the challenge and I understand it, although I’m going to present my understanding of how it corrects my previous incorrect logic and I would love if someone looked over what I’m saying below and told me if I REALLY understand it or not.

  1. The if statement of the for loop is something I touched upon but never in the right format. It involves a condition wherein two ASCII characters are separated by more than one and this is determined by adding 1 to one ASCII and subtracting another ASCII character from it. Previously I’d attempted this, tragically, in the reduce method:`
    nums = nums.reduce((prev, curr)=>{
    if(curr - prev > 1){
    missingNum.push(fromCharCode(prev + 1))
    }
    })

  2. Of course, reduce is not the correct method to use. Using it actually demonstrates a misunderstanding of its true function as one FCC member commented:

This isn’t how the reduce function is used. reduce takes an array of things of type A and turns it into a single value B, using the callback function to go through the array and sequentially merging each value into B.
It’s not a version of a loop, which is what you’re trying to use it for.
And you don’t need reduce here, it’s not the right tool: you have a loop, you can check the next value in the string in that loop.

  1. The method used above in the correct solution is a version of what I’d previously tried with a slightly different syntax that made all the difference. I’ll place them both below:
    if(numLet[i+1] - numLet[i] > 1){
    return String.fromCharCode(numLet[i]);
    }
    }
    }

    Above is a version of one attempt. Another form of this was trying to keep numLet[i+1] in the brackets or using the numLet[i]+1 in the if statement.

    if(numLet[i+1] - numLet[i] > 1){
    return String.fromCharCode(numLet[i]+1);
    }
    }
    }

    This works for the following reason. The missing number is 100. So, you want to compare the numbers. When you get to the first iteration, 97(index 0), you add one and minus the original number by the original plus one (98-97). You only get 1. Doesn’t satisfy. When you get to 99(index 2) and add one to the index, you end up with the element 101. 101-99 is 2 and greater than 1.
    Therefore, you will return using the String object conversion of a character code back to a string type with the following parameter: the index being converted will be the original index used in the problem, then the element at that index number plus one. That way, you don’t traverse over 100 to 101, but actually add 1 to 99 (which is at index 2…the i being referenced.)

Is this an accurate understanding of what has taken place?

SOLUTION BELOW:

function fearNotLetter(str) {
  var numLet = str.split("").map((newNum)=>{
    return newNum.charCodeAt();
  });
  for(var i = 0; i < numLet.length; i++){
  if(numLet[i+1] - numLet[i] > 1){
    return String.fromCharCode(numLet[i]+1);
  }
  }
}

fearNotLetter("abce");

Also, I’ve been working through why map() was a better choice then what I’d previously been trying to do. Does my reasoning make sense? Sorry for the long-winded post. I just wanted to make sure I really understand what has taken place and some of the lessons that I need to take away from it.

I was using a for loop and .push() to contain it within an empty variable I created at the beginning of the code. This created a lot of extra code and a bit of repetition in terms of the need of an iteration later in the code that might have necessitated me using another loop. Keep it DRY as they say. The map() with the return statement using charCodeAt() to return an array that already has converted things to ASCII saves me the extra code.
The for loop as I had been using it was a pastiche of different parts of the challenge that I tried to stuff into it when in fact I should have been thinking about the best fit of the for loop in the code. How can it be put in so that it does not stick out so awkwardly. Using map(), which creates a new array and iterates through it performing a function upon each element takes care of the awkwardness of my initial for loops and opens up the code to using the for loop in a more directed manner.