How can I do an asc and desc sort using underscore.js?

How can I do an asc and desc sort using underscore.js?

I am currently using underscorejs for sort my json sorting. Now I have asked to do an ascending and descending sorting using underscore.js. I do not see anything regarding the same in the documentation. How can I achieve this?

Solutions/Answers:

Solution 1:

You can use .sortBy, it will always return an ascending list:

_.sortBy([2, 3, 1], function(num) {
    return num;
}); // [1, 2, 3]

But you can use the .reverse method to get it descending:

var array = _.sortBy([2, 3, 1], function(num) {
    return num;
});

console.log(array); // [1, 2, 3]
console.log(array.reverse()); // [3, 2, 1]

Or when dealing with numbers add a negative sign to the return to descend the list:

_.sortBy([-3, -2, 2, 3, 1, 0, -1], function(num) {
    return -num;
}); // [3, 2, 1, 0, -1, -2, -3]

Under the hood .sortBy uses the built in .sort([handler]):

// Default is ascending:
[2, 3, 1].sort(); // [1, 2, 3]

// But can be descending if you provide a sort handler:
[2, 3, 1].sort(function(a, b) {
    // a = current item in array
    // b = next item in array
    return b - a;
});

Solution 2:

Descending order using underscore can be done by multiplying the return value by -1.

//Ascending Order:
_.sortBy([2, 3, 1], function(num){
    return num;
}); // [1, 2, 3]


//Descending Order:
_.sortBy([2, 3, 1], function(num){
    return num * -1;
}); // [3, 2, 1]

If you’re sorting by strings not numbers, you can use the charCodeAt() method to get the unicode value.

//Descending Order Strings:
_.sortBy(['a', 'b', 'c'], function(s){ 
    return s.charCodeAt() * -1;
});

Solution 3:

The Array prototype’s reverse method modifies the array and returns a reference to it, which means you can do this:

var sortedAsc = _.sortBy(collection, 'propertyName');
var sortedDesc = _.sortBy(collection, 'propertyName').reverse();

Also, the underscore documentation reads:

In addition, the Array prototype’s methods are proxied through the chained Underscore object, so you can slip a reverse or a push into your chain, and continue to modify the array.

which means you can also use .reverse() while chaining:

var sortedDescAndFiltered = _.chain(collection)
    .sortBy('propertyName')
    .reverse()
    .filter(_.property('isGood'))
    .value();

Solution 4:

Similar to Underscore library there is another library called as ‘lodash’ that has one method “orderBy” which takes in the parameter to determine in which order to sort it. You can use it like

_.orderBy('collection', 'propertyName', 'desc')

For some reason, it’s not documented on the website docs.

Related:  Smoothing arcs/plot points in D3.js/GeoJSON/TopoJSON/Shapefile (somewhere along the way)

Solution 5:

Underscore Mixins

Extending on @emil_lundberg’s answer, you can also write a “mixin” if you’re using Underscore to make a custom function for sorting if it’s a kind of sorting you might repeat in an application somewhere.

For example, maybe you have a controller or view sorting results with sort order of “ASC” or “DESC”, and you want to toggle between that sort, you could do something like this:

Mixin.js

_.mixin({
    sortByOrder: function(stooges, prop, order) {
      if (String(order) === "desc") {
          return _.sortBy(stooges, prop).reverse();
      } else if (String(order) === "asc") {
          return _.sortBy(stooges, prop);
      } else {
          return stooges;
      }
    }
})

Usage Example

var sort_order = "asc";
var stooges = [
  {name: 'moe', age: 40}, 
  {name: 'larry', age: 50}, 
  {name: 'curly', age: 60},
  {name: 'July', age: 35},
  {name: 'mel', age: 38}
 ];

_.mixin({
    sortByOrder: function(stooges, prop, order) {
    if (String(order) === "desc") {
        return _.sortBy(stooges, prop).reverse();
    } else if (String(order) === "asc") {
        return _.sortBy(stooges, prop);
    } else {
        return stooges;
    }
  }
})


// find elements
var banner = $("#banner-message");
var sort_name_btn = $("button.sort-name");
var sort_age_btn = $("button.sort-age");

function showSortedResults(results, sort_order, prop) {
    banner.empty();
    banner.append("<p>Sorting: " + prop + ', ' + sort_order + "</p><hr>")
  _.each(results, function(r) {
    banner.append('<li>' + r.name + ' is '+ r.age + ' years old.</li>');
  }) 
}

// handle click and add class
sort_name_btn.on("click", function() {
  sort_order = (sort_order === "asc") ? "desc" : "asc"; 
    var sortedResults = _.sortByOrder(stooges, 'name', sort_order);
  showSortedResults(sortedResults, sort_order, 'name');
})

sort_age_btn.on('click', function() {
    sort_order = (sort_order === "asc") ? "desc" : "asc"; 
    var sortedResults = _.sortByOrder(stooges, 'age', sort_order);
  showSortedResults(sortedResults, sort_order, 'age');
})

Here’s a JSFiddle demonstrating this: JSFiddle for SortBy Mixin

Related:  How to change the text of a label?