2

I have a list of names in JavaScript. What I'd like to do is get the list of unique names, but for that list of unique names also provide a count of how many there are in my original list. Furthermore, I need to sort my final list of unique names by count in descending order (then ascending order by name in case some have the same counts).

Here's what I have which is just a simple list of strings, that then gives me the list of unique names. From here, I'm not sure where to get the counts or how to then sort the unique list by counts. I'm thinking the final result will be either a 2D array of names and counts or 2 separate arrays, but I'm not sure how to go about this the best and most efficient way.

This is what I have so far:

Array.prototype.contains = function(v) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === v) return true;
  }
  return false;
};

Array.prototype.unique = function() {
  var arr = [];
  for (var i = 0; i < this.length; i++) {
    if (!arr.contains(this[i])) {
      arr.push(this[i]);
    }
  }
  return arr;
}

var uniqueAuthorNames = allAuthorNames.unique();
uniqueAuthorNames.sort();
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
Andy
  • 1,243
  • 3
  • 22
  • 40

4 Answers4

3

Use a hash map for counting unique elements and then sort the unique elements by two criteria:

var names = ["eve", "carl", "adam", "carl"];

var counts = names.reduce((counts, name) => {
  counts[name] = (counts[name] || 0) + 1;
  return counts;
}, {});

var uniques = Object.keys(counts);

uniques.sort((a, b) => counts[a] == counts[b] ? a.localeCompare(b) : counts[b] - counts[a]);

console.log(counts);
console.log(uniques);
Community
  • 1
  • 1
le_m
  • 19,302
  • 9
  • 64
  • 74
1

Supposing your array of names is in arr :

var i;
var o = {};
var len = arr.length;
for (i=0; i<len; i++) {
  o[arr[i]] = (o[arr[i]] || 0) + 1; 
}

At this stage, o will hold every unique name, with its count. You can then use the solution in Sorting JavaScript Object by property value

This will be

var sortable = [];
for (var name in o) {
  sortable.push([name, o[name]])
}
sortable.sort(function(a, b) {return b[1] - a[1]})
Community
  • 1
  • 1
Jerome WAGNER
  • 21,986
  • 8
  • 62
  • 77
  • Thanks Jerome. I just ran across this solution and it works perfectly. I'm just trying to figure out how to sort by the count in desc order based on the link you posted. But this is getting me on the right track now. – Andy Jun 14 '16 at 20:21
  • use return b[1] - a[1] instead of return a[1] - b[1] – Jerome WAGNER Jun 14 '16 at 20:22
1

This should be working for what you need.

Object.defineProperty (Array.prototype, 'getUniqueSorted', {
    enumerable: false,

    value: function () {
        var uniqarr = [];

        for (var i in this) {
            var index = uniqarr.indexOf (this.[i]);
            if (index == -1) {
                uniqarr.push (this [i])
            } else {
                uniqarr [index].count = uniqarr.count ? 2 : uniqarr.count+1;
            }             
        }

        uniqarr = uniqarr.sort(function(a, b){
            return (a.count | 1) - (b.count | 1)
        });

        return uniqarr;
    }
});

There's some other options to make more elegant.

    Object.defineProperty (Array.prototype, 'removeDuplicated', {
    enumerable: false,

    value: function () {
        var uniqarr = [];

        this.reduce(function(accum, current) {
            if (accum.indexOf(current) < 0) {
                accum.push(current);
            }

            return accum;
        }, uniqarr);

        return uniqarr.sort(function(a, b){
            return a.count - b.count
        });          
    }
});
0
    var names = ['john', 'paul', 'zack', 'john', 'sam', 'jill', 'paul', 'zack', 'zack'];
    var myNames = names.slice(0); // duplicate the array for getCount function otherwise sort will mess it up. 

    var myNames = names.sort(function(a, b) {
      if (getCount(a) !== getCount(b)) {
        return getCount(b) - getCount(a); // b - a to list larger counts first
      }
      if (a > b) {
        return 1;
      }
      return -1; // no case for if a == b because thats caught by getCount()
    });

/** 
** This function computes the number of times an element occur inside the array 
**/  
    function getCount(element) {
      var count = 0;
      for (var n = 0; n < myNames.length; n++) {
        if (myNames[n] === element) {
          count++;
        }
      }

      return count;
    }

console.log(myNames); // output your results
Yasin Yaqoobi
  • 1,888
  • 3
  • 27
  • 38