Search code examples
javascriptarrayssortingunique

Return sorted unique values from array, but if count is equal, return values in order


I am creating a function that takes in an array of unsorted integers and returns an array of the unique integers, sorted by frequency. However, if the integers have the same frequency, they will be returned in the original order of the input array. Here is my current function:

function uniqueUnionSorted(arr) {
  counter = {};
  for(var i=0; i<arr.length; i++) {
    if (arr[i] in counter) {
      counter[arr[i]] ++;
    } else {
      counter[arr[i]] = 1;
    }
  }
  sortedStrings = Object.keys(counter).sort(function(a,b) {
    return counter[b] - counter[a]
  });
  var sortedNumbers = sortedStrings.map(Number);
  return sortedNumbers;
}

So for an array like this:

arr = [1, 3, 2, 1, 5, 2, 1, 4]

the function should return:

[1,2,3,5,4]

However, my function is sorting the 5 and 4 and is returning:

[1,2,3,4,5]

Please help!


Solution

  • The cause of this reordering is that object properties that are numerical will come out ordered when using Object.keys().

    Instead of defining counter as an object, use a Map, which will retain the insertion order:

    function uniqueUnionSorted(arr) {
      var counter = new Map();
      for(var i=0; i<arr.length; i++) {
        counter.set(arr[i], (counter.get(arr[i]) || 0) + 1);
      }
      // Spreading the Map will produce an array of pairs
      var sortedNumbers = [...counter].sort(function(a,b) {
        return b[1] - a[1]; // sort by count
      }).map(a => a[0]); // only keep the values, not the counts
      return sortedNumbers; // Map keys retain original type, so they remain numeric
    }
    
    arr = [1, 3, 2, 1, 5, 2, 1, 4]
    
    console.log(uniqueUnionSorted(arr));