1

I am counting the frequency of numbers between 0 and 256 found in a sequence using a javascript array.

If I see the number 74 pop up I am storing it in the 74th index value (i.e. mysequence[74] = mysequence[74] + 1)

I can see the results tallied and its easy when scanning it visually to see that certain numbers (for example 65) has appeared much more often than others. I want to find the 10 numbers that appear most often.

I am concerned a simple sort will not retain the index value which is what I am using to track which number is associated with the counted frequency.

The only thought that comes to mind would be a brute force approach. Creating a function to look through all values one by one keeping the highest and ignoring all indexes that are part of an ignore list. Then running that function 10 times, each subsequent time passing the values of the indexes that have been assigned the top values.

Is there a way to get the numeric keys associated with the top 10 values without resorting to the approach above? (i.e. maybe converting my data to a different format and some fancy map sorting functions?)

Joseph U.
  • 4,457
  • 10
  • 41
  • 47
  • k-smallest (or k-biggest) is often an interview question. See https://stackoverflow.com/questions/5380568/algorithm-to-find-k-smallest-numbers-in-array-of-n-items for a discussion of the general algorithm. – Wyck Jan 21 '22 at 19:00
  • maybe a small data set would help to help better. – Nina Scholz Jan 21 '22 at 19:22

4 Answers4

4

You could get the indices and sort them by using the values and get the top wanted indices.

const
    values = [7, 3, 4, 5, 2, 8],
    indices = [...values.keys()].sort((a, b) => values[b] - values[a]);

console.log(indices.slice(0, 3));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

If you just sort it right away, you are definitely going to lose information about the indexes. What you can do is map the array with the values to an array with the index and the value (so that you don't lose information later), then you sort it, but you change the criteria of the sort method in order to get the indexes with top values.

const arr = [2, 1, 0, 3];

const getTopN = (arr, n = 10) => {
  const _arr = arr.map((value, index) => [value, index]);
  // by using b[0] - a[0] instead of a[0] - b[0] we can get the array in non-increasing order
  _arr.sort((a, b) => b[0] - a[0]) 
  return _arr.slice(0, n).map(([_, index]) => index);
}

console.log(getTopN(arr))

The getTopN function does the job.

1

There might be other ways, but what comes to me off the top of my head is to map the original array to a set of value/index pairs, sort the result based on value, then grab the last (or first) 10 items of the sorted array (depending on whether or not you did an ascending or descending sort).

yourArray.map((value, index) => ({ value, index }))
  .sort((a, b) => b.value - a.value)
  .slice(0, 10)
  .map(obj => obj.index);

You can omit the last map if you want to keep both the indices and the values that go with them in your result.

kshetline
  • 12,547
  • 4
  • 37
  • 73
0

I would store the values a bit differently (or add a step, where): they are mapped like [number, numberOfAppearances].

Then it's easy to sort them and get the first 10.

const randomIntFromInterval = (min, max) => {
  return () => Math.floor(Math.random() * (max - min + 1) + min)
}
const generateRndNum = randomIntFromInterval(0, 100)

const numArr = Array(1000).fill(0).map(_ => generateRndNum())

const tally = numArr.reduce((a, c) => {
  if (typeof a[c] === "undefined") a[c] = [c, 0]
  a[c][1] += 1
  return a
}, [])

const sorted = [...tally].sort(([k1, v1], [k2, v2]) => v2 - v1)

// getting the first ten:
sorted.length = 10

console.log(sorted)
muka.gergely
  • 8,063
  • 2
  • 17
  • 34