Getting an empty array on task 1 of Mini-linter extra credit

Hello everyone,

I am trying to replicate @partybarty_irl 's logic in order to fulfill task #1 of the ‘extra credits’, but all I am getting is an empty array:


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

let unnecessaryWords = ['extremely', 'literally', 'actually' ];
//1.SPLIT the string into into individual strings and save it to an array called storyWords
let storyWords = story.split(' ');
//2.LOG how many words are in the story
//console.log(storyWords.length);
//3.FILTER out the unnecessary words in the array and save them to a new array called betterWords
let betterWords = storyWords.filter( word => {
  if (!unnecessaryWords.includes(word)){
    return word;
  }
} );
//4.COUNT how many times overusedWords appear in the array
let overusedCount = Array(overusedWords.length).fill(0);

  betterWords.forEach (word => {
  overusedWords.forEach ((item, index) => {
    if (word === item){
      overusedCount[index]++;
    };
  } )
});
//5. COUNT how many sentences are in the story
let sentenceCount = 0;
betterWords.forEach ( word => {
  if (word[word.length-1] === '.' || word[word.length-1] === '!'){
    sentenceCount++;
  }
})
//console.log(sentenceCount);
//6.LOG the word count, sence count, and the number of times each overused word appears to the console. Use a function if possible
function logResults (par1, par2) {
  console.log(`There are ${par1} word` + (par1 > 1 ? 's ': ' ') + `and ${par2} sentence` + (par2 > 1 ? 's ': ' ') + `in this story.` );
overusedWords.forEach ((word, index) => {
  console.log(`The word ${word} appears ${overusedCount[index]} time` + (overusedCount[index] > 1 ? 's.': '.'))
})  
  
}
logResults(storyWords.length, sentenceCount);
console.log(betterWords.join(' '));
function even(num) {
  if (num % 2 === 0) {
    return true;
  } else {
    return false;
  }
};
let overusedCount2 = Array(overusedWords.length).fill(0);
let extraOne = betterWords.filter( word => {
  overusedWords.forEach ((item, index) => {
    if(item === word){
      overusedCount2[index]++;
      if (even(overusedCount2[index]) === false) {
        return word;
      }
    }
  } )

    
    
  
})
console.log(overusedCount2);
console.log(extraOne);

I am trying to use the same logic I used for step 4 (provided by @midlindner) in order to make it work with an indefinite number of elements in the overusedWords array, so I may be in over my head. Can you take a look and see what’s wrong? Thanks!

We shouldn’t need an if statement in the filter method callback since it (includes) is already a predicate function.

storywords.filter(word => !unnecessaryWords.includes(word))
const isEven = num => num % 2 === 0;

I’m not yet looking for errors as much as ways to simplify and refactor. Often times we spot errors during this process, and sometimes even remove the error just by rewriting the code.

let overusedCount = Array(overusedWords.length).fill(0);

  betterWords.forEach (word => {
  overusedWords.forEach ((item, index) => {
    if (word === item){
      overusedCount[index]++;
    };
  } )
});

The above logic is fine, but not as literal as it would be if we were more transparent. Nested forEach usually catches an eye.

  let grab = betterWords.filter(word => overusedWords.includes(word));

This list will have repeated items since every instance is appended to the output array. Now the words need only be counted.

  let freq = overusedWords.map(x => [x, 0]);

gives us an array of key, value pairs. There are a number of ways we can work with this array. For this demo let’s reach out to the Map class with the above iterable.

  let freqMap = new Map(freq);

Now we can iterate over grab and update the values.

  grab.forEach(x => freqMap.set(x, freqMap.get(x) + 1));

If what we want is an object, we can create one from this Map object.

  let freqObj = Object.fromEntries(freqMap)

None of the above is meant to drive home a point. Just a take on things.

I am analyzing your corrections and I am getting to the following conclusions (Please correct me if I am wrong):

  • .filter() by itself commands to return something to an array, so return word; is redundant; the resulting array consists of only the elements that meet the specified condition.
  • By applying a strict equality operator in the isEven, we are giving it a boolean property (This may have been discussed in one of the lessons but I am not really sure).

Sorry for the delay. Was busy with other things as well as the above reply edits.

filter will query every term in the target array against the conditional in the callback.

truthyTerms = target.filter(x => %x coerces to true by the condition%)

isEven is a predicate function that always returns a boolean. As well, and as you have observed, since equality is a comparison, it too yields a boolean. Hence, no need to explicitly return true nor false.

What this suggests is that we can forge a horseshoe in any number of ways; but, the horse pays the price if we get it wrong.

The focus is on simplifying and refactoring, still, at this point. How much of the above introduced logic do we really need? Is it necessary to have a word frequency count when all we are looking for is an overused word count in accumulated form? “50 words were found from the overused words catalog.” _Which ones, or how many times they appear is meaningless if the intention is to remove or replace them.

 > list1 = [2,4,6,8,10,12,14,16,18,20] 
<- (10) [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
 > list2 = [3,6,9,12,15,18,21,24,27,30]
<- (10) [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
 > list3 = [2,4,3,2,4,3,2,4,3]
<- (9) [2, 4, 3, 2, 4, 3, 2, 4, 3]
 > list3.filter(x => list1.includes(x))
<- (6) [2, 4, 2, 4, 2, 4]
 > list3.filter(x => list2.includes(x))
<- (3) [3, 3, 3]
 > freq = list1.map(x => [x, 0])
<- (10) [Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2), Array(2)]
 > fmap = new Map(freq)
<- Map(10) {2 => 0, 4 => 0, 6 => 0, 8 => 0, 10 => 0, …}
 > grab = list3.filter(x => list1.includes(x))
<- (6) [2, 4, 2, 4, 2, 4]
 > grab.forEach(x => fmap.set(x, fmap.get(x) + 1))
<- undefined
 > fmap
<- Map(10) {2 => 3, 4 => 3, 6 => 0, 8 => 0, 10 => 0, …}
 > fhash = Object.fromEntries(fmap)
<- {2: 3, 4: 3, 6: 0, 8: 0, 10: 0, 12: 0, 14: 0, 16: 0, 18: 0, 20: 0}

Sorry for the delay, I was busy with work and had not been able to look at this carefully; I am trying to digest all this (I am almost there with your post on refactoring step #4). I do have several questions on this one with the lists of numbers; I know what (almost) every line of code is doing, but I can’t figure out what the purpose of going through those lists is.
I see some things that I have only seen briefly in the lessons; do you recommend finishing the lessons and giving this a try after that? Or should I just get this over with and then go on? I get frustrated at times and wonder if there is something in following lessons that will clear all of that. Thanks, and sorry for taking advantage of your being this helpful.

1 Like

Above, pretend that list3 is betterWords and list1 and list2 are overusedwords. I used numbers because it was simpler working in the console. Why I created two of those lists was just to compare the interactions with list3. My main goal was to utilize iterators and minimize use of forEach.

Above we use,

filter
map
includes
forEach
Map constructor
fromEntries

The latter two likely don’t come up in any lessons, but the other four are covered in the unit on iterators, as I recall.

This project leaves a lot of wiggle room in terms of choosing techniques and logic. My goal above was to push the envelope.

This line,

freq = list1.map(x => [x, 0])

creates an array of key value pairs where x is the word, and 0 is the initialized frequency value. We cannot write it like this,

freq = list1.map(x => {x: 0})

since it will result in an array of empty objects. That is why I reached for the Map constructor since a Map object can be easily converted to an object. In the post above I included a link to the MDN page on Map.

As for whether you have enough information under your belt, one expects perhaps not. It may be beneficial to continue with the studies and bookmark this project for later. You can return to this topic at that time and ping me to re-engage. There are a other things to consider but I won’t go into it now. Keep you finger on the iterators button and continue to practice using them.

1 Like

Yeah, I think I am going to finish the JavaScript lessons and then try to do all the projects back to back to see if the information has really stuck. Thanks for the patience!

1 Like

Note that this topic has been split off the original. Bookmark this so you can find it later.

1 Like