Introduction to JavaScript - Mini Linter excercise - step 4, 5

Hi all, I’m newbi to coding. I’m struggling to understand why I’m having issues with step 4 of the following exercise
https://www.codecademy.com/courses/introduction-to-javascript/projects/mini-linter

MY CODE:
//4.
let reallyCount=0;
let veryCount=0;
let basicallyCount=0;

for (word of storyWords) {
if (word === ‘really’) {
return reallyCount += 1
} else if (word === ‘very’) {
return veryCount += 1
} else if (word === ‘basically’) {
return basicalllyCount += 1
}
}
//question: why is it not logging? :confused:
console.log(reallyCount);
console.log(veryCount);
console.log(basicallyCount);

ISSUES:
When I ask the computer to log, nothing gets logged (no error message either). This also impacts step 5 of the exercise. However, when I switch step 5, cut and paste it before step 4, it properly logs the number of senteces. Also reallyCount, veryCount, and basicallyCount get properlly logged to 0 if I ask that of the computer before the for(word of storyWords…etc… What am I missing?

MY CODE FOR STEP 5
//5. question: also this below doesn’t log, but if I cut and paste it above the for (word of storyWords), then it logs :confused:
let sentenceCounter=0;

storyWords.forEach(
function(word) {
if(word[word.length-1] === ‘.’ || word[word.length-1]===’!’) {
return sentenceCounter+=1;
}
}
);
console.log(sentenceCounter);

1 Like

return outside of function will raise an error. Remove that keyword and just accumulate the variable so the loop can run its course.

Do you have these three arrays in your initialization…

let overusedWords = ['really', 'very', 'basically'];

let unnecessaryWords = ['extremely', 'literally', 'actually'];

let replacements = ['quite', 'so', 'infact']

This will seem right out in left field, but let’s make a histogram of overUsedWords…

let histo = {};
overUsedWords.forEach(x => histo[x] = 0);

Now we can iterate over betterWords and build up a total count on each of the overUsedWords…

for (let word of betterWords) {
    if (overUsedWords.includes(word)) {
        histo[word] += 1;
    }
}

Now we can log it out

console.log(`Overused Word Count`)
for (let word in histo) {
    console.log(`${word}: ${histo[word]}`);
}
Overused Word Count
really: 2
very: 5
basically: 1

Another approach would be to use .filter to create a smaller array of just the filtered words, then make a histogram from that.

let excessWords = betterWords.filter(word => overUsedWords.includes(word));
let histo = {};
excessWords.forEach(x => histo[x] = 0);
for (let word of excessWords) {
    histo[word] += 1;
}
console.log(`Overused Word Count`)
for (let word in histo) {
    console.log(`${word}: ${histo[word]}`);
}
Overused Word Count
really: 2
basically: 1
very: 5

That is not to say these are any better than the method you chose, just different. We can explore iterators in all manner of ways.

Take for instance step 5, sentence count. We know that words followed by a full stop will have that stop attached in the betterWords list, as your code also shows. Given a list of full stop tokens,

let fullStops = 0;
for (let token of '.:?!') {
  fullStops += betterWords.filter(word => word.indexOf(token) > -1).length;
}
console.log(`Sentence Count: ${fullStops}`);

Notice that it won’t matter which order we do step 4 or 5.

3 Likes

Roy, THANKS! Something so simple indeed solved the matter. I removed the keyword return and it works.

(However, my inexperience in programming doesn’t allow me to fully learn from your explanation. My background in in music and business management, no previous coding whatsoever. Apologies in advance :sweat_smile:) and let’s do this

So:

  1. you mention “return outside of function will raise error”.
    1.1: How is it “outside of function” if it’s in the code block, where I usually see return being used in other exercises.
    1.2. Apparently I have the misconception that having ‘return’ is always a safe bet (I did mistakes for forgetting to place it … now I see I can also make mistakes for using it). I don’t understand when exactly I need to use ‘return’ and when not to…

  2. I have the arrays overusedWords and unnecessaryWords . (it came already written with the exercise. I don’t see any replacements array but I guess that relates with the optional suggestions of the exercise at the end, which … I’m yet to tackle :grin:

  3. With regards to the histo, and the tokens - I guess this is knowledge I’m missing, so I’ll keep them in mind and do some research :slight_smile:

Again, thank you so much for taking the time to help me!
Pedro

2 Likes

for is an iterator, granted, but it does not take a callback like other iterators do, and hence they will have return in the callback. We can only ever use return inside a function (including callback functions).

It will come up at some point, so stick with what you know and feel comfortable. You do seek out two of the four full stop tokens, but that goes under the assumption the other two, : and ? do not exist in the text. Who knows? They might if we could not previously examine the text before running the linter.

There are two ways to iterate over a string or an array using for

for (let i = 0; i < obj.length; i++) {

}

which iterates over the indices. The values are, obj[i].

for (let val of obj) {

}

which iterates over the values in the string or array. We use the special keyword that was introduced in ECMA2015, of as opposed to the in keyword which iterates keys in an object. We should never use in when iterating arrays or strings (future caution).

Notice how filter uses a predicate function to select which items will be in the final array. Our predicate is,

word => word.indexOf(token) > -1

which will return true or false. indexOf will return an index, 0 to length - 1, or -1 if not found. We are creating a transient array for each token, which array we need only the length of to add to the running total.

Again, this is not better than any other approach, such as yours, just simpler. A naive learner (one with little or no intuition built up) will not likely come up with this on their own. Work with what you know, and in the review process look for other approaches once your knowledge base is expanded.

2 Likes

Thanks a lot Roy! Really helpful feedback :slight_smile:

2 Likes

Since this is really an exercise on iterators, then we might continue to explore potential replacement of the mighty, for.

fullStops = 0;
'.:?!'.split('').forEach(token => {
  fullStops += betterWords.filter(word => word.indexOf(token) > -1).length;
});
console.log(`Sentence Count: ${fullStops}`);
1 Like

Nice! Let Me see if I understood what you did there:
So, what I can interpret is that:

  1. you are creating an “implicit array” by splitting the string ‘.:?!’ into each individual symbol via space separator (didn’t know that it was possible to run methods on “implict arrays” without first assigning them to a variable. Am I interpreting this correctly?)
  2. then, forEach element/symbol (argument token) you are going to run some functionality that lets you add +1 to the fullStops counter. First it will count all ‘.’, then count all ‘:’ and so on. By the end of which you will have all full stops counted, which should equal the number of sentences.
  3. As for the functionality itself, the number you are adding to the initial fullStops value is the length of the array

The resulting filtered array should be, for each token, the number of times that specific token is present in betterWords.
I’m just trying to understand how is it that

results in that. :sweat_smile:

2 Likes

That’s actually an empty space, which means to split on each character. I use an implicit array so it has a forEach method. In this particular instance we could have created a standalone array but then it would be sitting in memory taking up space afterward. This way it is transient, just like the four filter arrays. They exist only as long as it takes to find the length.

The length of the filtered arrays is, as you deduce, the number of instances of that full stop. We’re not concerned with where they are, just how many. It is that number that gets added to fullStops. +1 doesn’t come into it, unless that is the actual count.

Array.filter() takes a predicate function as an argument. As we iterate over the betterWords array, we check if there is a token present. String.indexOf() returns the index if one is present, else it returns -1. We want to filter out all the words that possess a token. That will give us an array to check the length of.

2 Likes

Hi Roy,
Great feedback as usual!

I was still figuring how the -1 was checking for that, but I know understand: an index is => 0. The condition > -1 forces that check. Got it, thanks :slight_smile:

1 Like