Array Sort issues

Can anyone tell me why this isn’t sorting correctly?

let input = 
"Every book is a quotation; and every house is a quotation out of all forests, and mines, and stone quarries; and every man is a quotation from all his ancestors. ";
 
function wordCountEngine(document) {
  let regEx = /[^\w\s]/g;
  let clean_input =  document.trim().toLowerCase().replace(regEx,'').split(' ');
  let word_list = [];
  return  clean_input.reduce((ans, current, idx, source)=> {
    let count = source.filter((val) =>  val === current).length;
    let isCounted = word_list.includes(current);
    word_list.push(current);
    return (isCounted) ? ans :  [...ans,[current, count.toString()]];
  },[]).sort((a,b)=> parseInt(a[1]) < parseInt(b[1]));
}

console.log(wordCountEngine(input));

Expected output

[["and","4"],["every","3"],["is","3"],["a","3"],["quotation","3"],["all","2"],["book","1"],["house","1"],["out","1"],["of","1"],["forests","1"],["mines","1"],["stone","1"],["quarries","1"],["man","1"],["from","1"],["his","1"],["ancestors","1"]]

Actual output

[ [ 'all', '2' ], [ 'every', '3' ], [ 'is', '3' ], [ 'a', '3' ], [ 'quotation', '3' ], [ 'and', '4' ], [ 'stone', '1' ], [ 'house', '1' ], [ 'of', '1' ], [ 'book', '1' ], [ 'forests', '1' ], [ 'mines', '1' ], [ 'out', '1' ], [ 'quarries', '1' ], [ 'man', '1' ], [ 'from', '1' ], [ 'his', '1' ], [ 'ancestors', '1' ] ]

I’m not at all sure how the ‘and’ and ‘all’ arrays are mixed up.

Your sort()'s callback is wrong because it only returns either 0 or 1.

Returning 0 is an assertion for two keys having an equal weight. You either have to return -1 for things that comes before and 1 for things that comes after.

1 Like

Thank you , I was not seeing that. I now have .

.sort((a,b)=> parseInt(b[1]) - parseInt(a[1]));

And it seems to be working much better.

Problem
Implement a document scanning function wordCountEngine, which receives a string document and returns a list of all unique words in it and their number of occurrences, sorted by the number of occurrences in a descending order. If two or more words have the same count, they should be sorted according to their order in the original sentence. Assume that all letters are in english alphabet. You function should be case-insensitive, so for instance, the words “Perfect” and “perfect” should be considered the same word.

The engine should strip out punctuation (even in the middle of a word) and use whitespaces to separate words.

Analyze the time and space complexities of your solution. Try to optimize for time while keeping a polynomial space complexity.

Solution:

/*******************
** Steps to scanning the document
** 1. Clean the input by striping all punctuation and extra spaces
** 2. Transform (with a map) the values to include the count
** 3. Filter out any duplicates
** 4. Stable Sort the output. 
*/


Object.defineProperty(Array.prototype, 'stableSort', {
  configurable: true,
  writable: true,
  value: function stableSort (compareFunction) {
    'use strict'

    var length = this.length
    var entries = Array(length)
    var index

    // wrap values with initial indices
    for (index = 0; index < length; index++) {
      entries[index] = [index, this[index]]
    }

    // sort with fallback based on initial indices
    entries.sort(function (a, b) {
      var comparison = Number(this(a[1], b[1]))
      return comparison || a[0] - b[0]
    }.bind(compareFunction))

    // re-map original array to stable sorted values
    for (index = 0; index < length; index++) {
      this[index] = entries[index][1]
    }
    
    return this
  }
})



function wordCountEngine(document) {
  let word_list = [];
  return  clean_input(document).map((current, idx, source)=> {
    let count = source.filter((val) =>  val === current).length;
    return [current, count.toString()];
  }).filter((val)=>{
    let isCounted = word_list.includes(val[0]);
    word_list.push(val[0]);
    return !isCounted; 
  }).stableSort((a,b)=> {
    return b[1] - a[1];
  });
}

var clean_input = (input)=> {
  let regEx = /[^\w\s]/g;
  return input.trim().toLowerCase().replace(/\s\s+/g,' ').replace(regEx,'').split(' ');
}