Here is a solution that avoids sorting by collecting the entries of the word count Map()
in an object by count value. The result is then the last 10 items in the Object.entries()
of this object. It should be noted that this relies on the ordering of the object keys which has been historically underspecified but, especially for integer keys as used here, offers predictable, ascending ordering in line with updates to the specification. – see: Does ES6 introduce a well-defined order of enumeration for object properties?
This solution has the added benefit of returning arrays of words with equal counts rather than the arbitrary cutoff that the solutions using sort()
introduce.
const input = [ "this", "is", "a", "test", "which", "word", "wins", "top", "i", "don't", "know", "off", "hand", "do", "you", "this", "a", "a", "this", "test", "a", "a", "do", "hand", "hand", "a", "whatever", "what", "do", "do"];
let counts = new Map(), i;
for (i = 0; i < input.length; i++) {
counts.set(input[i], (counts.get(input[i]) ?? 0) + 1);
}
let countHash = {};
counts.forEach((count, word) => (countHash[count] ??= []).push(word));
let result = Object.entries(countHash);
if (result.length > 10) result = result.slice(result.length - 10);
// output
for (let j = result.length - 1; j >= 0; j--) {
console.log(JSON.stringify(result[j]));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
To avoid the uncertainties of ordering/sort complexity of the object used to hash the counts Map using the count value as key, one can use a sparse array instead by simply replacing the object assignment with an array assignment and using the count value as index.
let countArr = [];
counts.forEach((count, word) => (countArr[count] ??= []).push(word));
Object.entries()
called on a sparse array respects holes and returns only existing [key, value]
pairs. (This is true of Object.keys()
and also iterating using for...in
).
const input = [ "this", "is", "a", "test", "which", "word", "wins", "top", "i", "don't", "know", "off", "hand", "do", "you", "this", "a", "a", "this", "test", "a", "a", "do", "hand", "hand", "a", "whatever", "what", "do", "do"];
let counts = new Map(), i;
for (i = 0; i < input.length; i++) {
counts.set(input[i], (counts.get(input[i]) ?? 0) + 1);
}
let countArr = [];
counts.forEach((count, word) => (countArr[count] ??= []).push(word));
let result = Object.entries(countArr);
if (result.length > 10) result = result.slice(result.length - 10);
// output
for (let j = result.length - 1; j >= 0; j--) {
console.log(JSON.stringify(result[j]));
}
// Output of this answer
[
[6, ['a']],
[4, ['do']],
[3, ['this', 'hand']],
[2, ['test']],
[1, ['is', 'which', 'word', 'wins', 'top', 'i', "don't", 'know', 'off', 'you', 'whatever', 'what']]
]
// Output using sort
[
[6, 'a'],
[4, 'do'],
[3, 'this'],
[3, 'hand'],
[2, 'test'],
[1, 'is'],
[1, 'which'],
[1, 'word'],
[1, 'wins'],
[1, 'top']
]
// [ 1, 'i' ],
// [ 1, "don't" ],
// [ 1, 'know' ],
// [ 1, 'off' ],
// [ 1, 'you' ],
// [ 1, 'whatever' ],
// [ 1, 'what' ]