Mini Linter Item 8


#1

I’m trying to get through this with a brain that hasn’t done math since high school. Yowza.

I’m working on Item 8, the second suggestion of additional coding…

I found this on stackoverflow and tried to adjust it to our terms, but am getting errors (and am struggling to understand each piece, it’s only useful to me if I can integrate it)

Can anyone help me read through this using the Mini Linter code??? My brain is on fire.

Thxzzzzz


#2

In statistics, the mode is the value that appears most often in the sample space.

The above function creates a frequency table (histogram) of all the items in the array. Those that appear multiple times result in an increment of their count. The maxCount variable keeps track of the highest number arrived at so far, and at the completion of the function returns the element it has associated with that amount.

Is that function something we want to plug in to lesson code? Can’t say, just now, but if you post a link to the project we can take a closer look.


#3

Hi mtf! Thank you for your time, I reeeeeeally apprecaite it!

here is my lesson code (and my attempt to modify the above code into it) https://gist.github.com/e9726ade1a9fc83f61d1eac6d8eb1ff1


#4

This is the link I meant, above…

Mini Linter

Given an array of unordered mixed data, the modeMap object will consist of the Set of data values as keys, meaning there would be no duplicates, and each corresponding value would be 1 or more.

const keySet = new Set(array);
 > str = "a quick brown fox jumps over the lazy dog"
=> 'a quick brown fox jumps over the lazy dog'
 > keySet = new Set(str.split(' '))
=> Set { 'a', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog' }
 > 

With that in mind (no repeated keys) it is easier to see how that count is achieved.

var key = array[i];
if (modeMap[key] === null) modeMap[key] = 1;
else modeMap[key]++;

If the key does not exist, a polling of that key will return null, hence the key is created with an initial value of 1. Otherwise the value is incremented.

This is practical for some purposes but for this excercise is overkill since we are not looking for the mode, but repeated words that are in a predefined list. It is those words we need to seek out in the text. For that we have the filter iterator.

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

// filter overused words

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

console.log(excessWords.length);
console.log(excessWords);

The code does not remove the words since we are only reporting to the user that they exist, and how many times. As author they would need to edit the text manually.


Addendum

Here is the above Set played out in finding the mode…

const sample = [1,2,3,4,3,2,1,2,3,4,5,6,7,6,5,4,5,6,7,8,9,8,7,6,5,4,2,3,1,2];

const mode = array => {
  let keySet = new Set(array);
  let modeMap = {};
  let el = null;
  let maxValue = 1;
  keySet.forEach(key => modeMap[key] = null);
  array.forEach(key => modeMap[key]++);
  for (let key in modeMap) {
    if (modeMap[key] > maxValue) {
      el = key;
      maxValue = modeMap[key];
    }
  }
  return el || 'None';
};

console.log(mode(sample));               // ->  2
console.log(mode([1,2,3,4,5,6,7,8,9]));  // ->  None
console.log(mode([]));                   // ->  Nobe

Furthermore,

The for loop can be abstracted away into a forEach callback,

  Object.keys(modeMap).forEach(key => {
    if (modeMap[key] > maxValue) {
      el = key;
      maxValue = modeMap[key];
    }
  });

Following we cache the progression through the array item frequencies in a global object as a test scenario:

const sample = [1,2,3,4,3,2,6,7,3,4,5,6,2,6,5,4,5,6,7,8,9,8,7,6,5,4,2,3,1,7];

const mode = (array, cache=[]) => {
  let keySet = new Set(array);
  let modeMap = {};
  let el = null, obj = null;
  let maxValue = 1;
  keySet.forEach(key => modeMap[key] = null);
  array.forEach(key => modeMap[key]++);
  Object.keys(modeMap).forEach(key => {
    obj = {};
    if (modeMap[key] > maxValue) {
      el = key;
      maxValue = modeMap[el];
      obj[el] = maxValue;
      cache.push(obj);
    }
  });
  return el || 'None';
};

let master = [];
console.log(mode(sample, master),'\t', master,'\n');
master = [];
console.log(mode([1,2,3,4,5,6,7,8,9], master),'\t', master,'\n');
master = [];
console.log(mode([], master),'\t', master);
6 	 [ { 1: 2 }, { 2: 4 }, { 6: 5 } ] 

None 	 [] 

None 	 []

This is all intuitive coding as one might have guessed by now. The thing that alludes me is how to return the object. I’m currently using the cache as a brute force way of keeping the evidence intact. I’d rather be able to return the last object cached, if it exists.


#5

Within the function, you could use a Map to create a histogram of word frequencies. Each word would be serve as a key in the Map.

See Map.

To populate the histogram, loop through the Array of words. Whenever you find a word that is not yet in the Map, you canset the value for the key for that word to 1. If the word is already in the map, increment its frequency by 1.

Finally, return the key, or word, that has the highest frequency, or return both the word and the associated frequency.

Alternatively, you could go beyond item 8 by inverting the entire histogram Map to create a new Map in which the frequencies from the original Map become the keys, each of which maps to an Array of the words that occur with that frequency. Return the new inverted Map. Then, outside the function, you would be able to list the words by frequency in ascending or descending order, or whatever order you want.

Added on January 1, 2018:

Below is a rough draft that you can refine as appropriate. For example, it can be modified to convert all words to lowercase prior to computing the frequencies.

var histogram = (words) => {
  let hist = new Map()
  words.forEach(function(word) {
    if (hist.has(word)) {
      hist.set(word, hist.get(word) + 1);
    } else {
      hist.set(word, 1);
    }
  });
  return hist;
}

#6

This essentially replaces the first six lines of my example, which was only intended to show the separate moving parts. Great example, @appylpye.

My problem above is not being able to return an object:

{ 6: 5 }

as in,

return { el: maxValue };

It comes back as,

{ el: 5 }

That is why I introduced the global to capture the sequence of progression as maxValue increases. The last object in the array is the desired return value.


#7

Y’all are way ahead of me… but I’ll be reading all this for the next year of my life until I understand it!

Maybe I can get some guidance as to how to use the formulas I’ve already been studying to work on Item 8.2? I think statistics will come a little later for me
signed
–totalbeginner :sweat_smile:


#8

That is the extra study part which is optional, for now, but you can always come back to it and work on it some more. Mark it as complete if you just want to continue and return later.

8.2 is looking for mode, this time, so either of the methods shown above will work. If we are confined to only what you know up to this point, that will take some thought.

Here is a hybrid of both Glenn’s and my examples (however it uses Map)…

const mode = words => {
  let hist = new Map();
  words.forEach(function(word) {
    if (hist.has(word)) {
      hist.set(word, hist.get(word) + 1);
    } else {
      hist.set(word, 1);
    }
  });
  let el = null;
  let maxValue = 1;
  hist.forEach((value, key) => {
    if (value > maxValue) {
      maxValue = value;
      el = key;
    }
  });
  return el || 'None';
};

Or use the code in your opening post, which will perform the same task.


#9

Thank you :slight_smile: I’ve been working using only mode, and here is what I’m using…

function mode(betterWords) {
return betterWords.sort((a,b) =>
betterWords.filter(word => word === a).length - betterWords.filter(word => word === b).length).pop();
}

console.log(mode(betterWords));

which is returning “the”. I’m wondering how I can change this to include integers as well (there are some numbers in the betterWords arr)?
Also when I changed the betterWords.filter(word => word === b).length).pop();

to being betterWords.filter(word => word === 1).length).pop(); (the ‘b’ became a ‘1’), the console logged “really” instead of “the”… why???

:thinking:


#10

Still trying to reason out the logic in your example. I did test the mode function from above it works perfect, returning the.

Regardless how we construct it, we do need a histogram. A really clunky way (probably tricky) might be to sort the array, then iterate over it. Create an empty array to contain the following: Start by putting the first word into its own array, then check the second against that array. If it matches, push it into that arrray; if it does not match then start a new array with that word in it, and carry on. Finally do a length check to find the longest array. There is your mode.


#11

8 posts were split to a new topic: Probably very messy and not most efficient way