2

Possible Duplicate:
Sorting JavaScript Object by property value

I want to get the top results for some value within my JSON. Easier explained with the example:

var jsonData = {
  bom: [
        {
            "Component":"Some Thing",
            "Version":"Version ABC",
            "License":"License ABC",
        },
        {
            "Component":"Another Thing",
            "Version":"Version XYZ",
            "License":"License ABC",
        }, 
        etc ....
       ]
}

So my goal is to determine that "License ABC" or another has X number of occurrences and then I want to be able sort those key:val pairs to insert into into the DOM as "The top X most popular licenses are:

  • License ABC - 100
  • License XYZ - 70
  • License 123 - 25

Right now I have this:

var countResults = function() {
    var fileLicenses = [];

    for ( var i = 0, arrLen = jsonData.files.length; i < arrLen; ++i ) {
        fileLicenses.push(jsonData.files[i]["License"]);
    }

    keyCount = {};
    for(i = 0; i < fileLicenses.length; ++i) {
        if(!keyCount[fileLicenses[i]]) {
            keyCount[fileLicenses[i]] = 0;
        }

        ++keyCount[fileLicenses[i]];
    }

    console.log( keyCount );
}();

Which get's me most of what I want, an object with key : values

{
    thisKey : 78,
    thatKey :125,
    another key : 200,
    another key : 272,
    another key : 45,
    etc ...
}

But I don't know how to do anything with that. I just need to sort the numeric right column and have the associated keys stay along for the ride. Thoughts? Thank you!

Community
  • 1
  • 1
Matt
  • 101
  • 2
  • 7

1 Answers1

6

You can't sort an object by it's values. What you can do is to transform it to an array of objects and sort that instead. Something like:

var rank = function(items, prop) {

  //declare a key->count table
  var results = {}

  //loop through all the items we were given to rank
  for(var i=0;len=items.length;i<len;i++) {

    //get the requested property value (example: License)
    var value = items[i][prop];

    //increment counter for this value (starting at 1)
    var count = (results[value] || 0) + 1;
    results[value] = count;
  }

  var ranked = []

  //loop through all the keys in the results object
  for(var key in results) {

    //here we check that the results object *actually* has
    //the key. because of prototypal inheritance in javascript there's
    //a chance that someone has modified the Object class prototype
    //with some extra properties. We don't want to include them in the
    //ranking, so we check the object has it's *own* property.
    if(results.hasOwnProperty(key)) {

      //add an object that looks like {value:"License ABC", count: 2} 
      //to the output array
      ranked.push({value:key, count:results[key]}); 
    }
  }

  //sort by count descending
  return ranked.sort(function(a, b) { return b.count - a.count; });
}

Usage:

var sorted = rank(jsonData.bom, "License");
var first = sorted[0].value;

/code not tested

jevakallio
  • 35,324
  • 3
  • 105
  • 112
  • Thanks fencliff! Plugged it in and it works great. Still need some time to understand the logic but just what I needed. Thanks! – Matt Jan 13 '13 at 03:50
  • @Matt I added some comments to the code to explain the logic. If the solution works, don't forget to mark the answer as accepted! – jevakallio Jan 13 '13 at 15:05
  • Wow. Really appreciate the comments Fencliff. The solution worked great from the get go but, it's always better to understand what you're plugging in! This helps. Thanks again! – Matt Jan 14 '13 at 17:43
  • @Matt, you're welcome. I wouldn't use any code I found on the internet unless I understood it, either :) – jevakallio Jan 14 '13 at 17:49