5

I'm trying to sort an array of objects by the average property in descending order - so the largest average is first - but am not able to using underscore.js. Below is my attempt:

var jsonData = [
{
    "title": "Dear Kitten",
    "totalCount": 1689,
    "average": 241
},
{
    "title": "Weird Things All Couples Fight About",
    "totalCount": 9966,
    "average": 1424
},
{
    "title": "If Disney Princesses Were Real",
    "totalCount": 16567,
    "average": 2367
},
{
    "title": "Secret Tricks With Everyday Objects",
    "totalCount": 24884,
    "average": 3555
},
{
    "title": "The Coolest Travel Hacks",
    "totalCount": 41847,
    "average": 8369
},
{
    "title": "5 Ways You're Drinking Coffee Wrong",
    "totalCount": 55673,
    "average": 7953
},
{
    "title": "The Perfect Way To Pour A Beer",
    "totalCount": 58097,
    "average": 58097
},
{
    "title": "Fruit You're Eating Wrong",
    "totalCount": 65570,
    "average": 32785
},
{
    "title": "Your Cat Is Judging You",
    "totalCount": 78952,
    "average": 11279
},
{
    "title": "3rd Date vs 30th Date",
    "totalCount": 84394,
    "average": 14066
}
];

console.log(_.sortBy(jsonData, "average"));

jsFiddle

16
  • 1
    ?? Looks like it's working just fine. The result is sorted in order of the value of the "average" property. Commented May 10, 2015 at 18:57
  • 1
    You aren't including underscore in your fiddle: jsfiddle.net/y7h9cu6p/1 Commented May 10, 2015 at 18:57
  • @RobM. ? it was there when I tried it just now. (It's an "external resource" in the OP's fiddle.) Commented May 10, 2015 at 18:58
  • 2
    That looks like it is correctly sorted. Is the problem that you want it in the opposite order, with the largest average first? Use .reverse() after the sort, or provide your own iteratee that reverses it, e.g. function( item ) { return -item.average; }. Commented May 10, 2015 at 19:05
  • 1
    You don't have JSON. You have a JS array containing JS objects. Commented May 10, 2015 at 19:14

1 Answer 1

4

The issue here is that you wanted the array to be sorted in descending order by average, instead of the default ascending order.

You could do this by providing a custom iteratee to the _.sortBy() function:

_.sortBy( jsonData, function( item ) { return -item.average; } )

Updated fiddle

But I don't recommend that. It would be much better to simply use the native JavaScript [].sort() method and provide it a comparison function:

jsonData.sort( function( a, b ) { return b.average - a.average; } )

Better fiddle

If you were sorting a very large array, this would also be faster than using _.sortBy(). Look at the source code for _.sortBy() to see why:

_.sortBy = function(obj, iteratee, context) {
  iteratee = cb(iteratee, context);
  return _.pluck(_.map(obj, function(value, index, list) {
    return {
      value: value,
      index: index,
      criteria: iteratee(value, index, list)
    };
  }).sort(function(left, right) {
    var a = left.criteria;
    var b = right.criteria;
    if (a !== b) {
      if (a > b || a === void 0) return 1;
      if (a < b || b === void 0) return -1;
    }
    return left.index - right.index;
  }), 'value');
};

It's doing quite a bit of work in addition to the .sort() call - and this code is just the tip of the iceberg, the helper functions it calls like cb() do a lot of work too.

Why do all that when it's just as easy to call .sort() directly yourself?

Also, it takes a close reading of that lengthy .sortBy() source to be sure that it does a numeric sort instead of a lexicographic sort - and the documentation doesn't say!

A lexicographic sort (aka alphabetic sort) is where the values are sorted as strings, not as numbers. So for example it would use this order:

[ 1424, 2367, 241, ... ]

When you call the native array .sort() yourself, you can easily verify that it uses a numeric sort: the value b.average - a.average is always a number.

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.