Two bugs
There is a bug when you have only less than two unique sizes. Trying to access an undefined array newArr[newArr.length-1][1], newArr[newArr.length-2][1]
throws if newArray.length < 2
Bug in hiding waiting to pounce. The variable key
has not been declared and thus has been created in the global scope. This is bad mistake and can result in very hard to find bugs in totally unrelated code. You should use "use strict" to catch such errors early.
General review notes
- Spaces between operators , spaces after
for
, if
, else
, ,
, and =>
and befor else
and =>
- There is no need to create the array
result
, you can create it as you return it. EG return [newArr[newArr.length-1][1], newArr[newArr.length-2][1]];
or return [newArr.pop()[1], newArr.pop()[1]];
- The arrays and
map
should be constants as they do not change.
- Try to avoid using
for in
loops they have some problems that make them next to useless. Rather use for of
- Converting the map to an array and then sorting, just to find the top to is overkill. Sorts are complex, and you have already passed over each item, and thus know what the max values are.
- Naming
map
is not a great name. It is a map that holds counts, so counts
is the better name
- For simple
if else
statements use the simplest form you can. eg you have if (!foo) {/* do not foo */} else {...}
the not !
is redundant if you reverse the order to if (foo) {... } else {/* do not foo */}
- Use the shorter form of arrow function if you are just returning a value.
.sort((a, b) => { return a[0] - b[0] });
can be .sort((a, b) => a[0] - b[0]);
- Sort sorts in place, you don't need to passing it to another array.
Rewrite using your approach
If there are no items to produce any of the top two then returns undefined
in its place. Needs to check the sorted array size to see if it can return any values.
Note that because it pushes the entries directly to the sorted
array the count and items have switched places in the arrays.
function findTopTwo(arr) {
"use strict";
const counts = {}, sorted = [];
for (const item of arr) {
counts[item] = counts[item] ? counts[item] + 1 : 1;
}
sorted.push(...Object.entries(counts));
if (sorted.length === 0) { return [] }
if (sorted.length === 1) { return [sorted[0][0]] }
sorted.sort((a, b) => a[1] - b[1]);
return [sorted.pop()[0], sorted.pop()[0]];
}
Avoiding the sort
This looks for the top two as you count them. It avoids the sort so is less complex and uses less memory.
function findTopTwo(arr) {
var maxA = 0, maxB = 0, itemA, itemB;
const counts = {};
for (const item of arr) {
const count = (counts[item] = counts[item] ? counts[item] + 1 : 1);
if (count > maxA && item !== itemB) {
if (item !== itemA && maxA > maxB) { [maxB, itemB] = [maxA, itemA] }
[maxA, itemA] = [count, item];
} else if (count > maxB && item !== itemA) { [maxB, itemB] = [count, item] }
}
return maxA > maxB ? [itemA, itemB] : [itemB, itemA];
}