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();
4
  • 2
    What is an example of input and output? Commented Jun 14, 2016 at 20:09
  • why a new "contains" method when you already have indexOf Commented Jun 14, 2016 at 20:09
  • @JeromeWAGNER Even then, we have includes. Commented Jun 14, 2016 at 20:12
  • 1
    just my 2cts but you should avoid adding methods on the native Array prototype. cf for instance stackoverflow.com/questions/948358/… Commented Jun 14, 2016 at 20:27

4 Answers 4

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);

Sign up to request clarification or add additional context in comments.

3 Comments

You can more simply do uniques.sort((a, b) => counts[b] - counts[a])
@Hamms Doesn't this cause undefined ordering for when counts[b] == counts[a]?
oh, very true; I missed the secondary ordering requirement
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]})

2 Comments

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.
use return b[1] - a[1] instead of return a[1] - b[1]
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
        });          
    }
});

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.