41

I'm using Javascript sort (with Underscore.js):

_.sortBy(["Bob", "Mary", "Alice"], function (name) {return name})
> ["Alice", "Bob", "Mary"]

I would like the array to return the other way. How do I do that?

["Mary", "Bob", "Alice"]

I don't want to reverse it after it's sorted - I want it to be created the other way around the first time.

Thanks.

2
  • 1
    You realise that ultimately it might just be faster to sort the array normally, and then call reverse()? Commented Jan 2, 2012 at 18:29
  • Sorting and then reversing would also be a lot more readable than other options. Commented Jan 2, 2012 at 18:42

4 Answers 4

80

Instead of throwing underscorejs away, I'd rather use it together with Array.reverse to utilize the best of both.

_.sortBy(["Bob", "Mary", "Alice"], function (name) {return name})
 .reverse()
Sign up to request clarification or add additional context in comments.

4 Comments

Also, instead of function(name) {return name} you can just use underscore's _.identity function: _.sortBy(["Bob", "Mary", "Marley", "Alice"], _.identity).reverse()
I wouldn't call this more elegant because the .reverse() call adds another cycle through the array. So it's actually less efficient than just sorting in reverse as Felix has suggested.
"It's easier to make good code fast than to make fast code good." (Attribute this to some Guru, I can't recall who said it before) This is more "elegant", if speed is what is needed the default sort might be enough; but if speed is the main concern JS is not the fastest technology around.
This is kind of performing the loop twice. 1st iteration. _.sortBy(["Bob", "Mary", "Alice"], function (name) {return name}) 2nd iteration .reverse() Better to handle within the _sortBy
35

I would just do what Underscore does under the hood: use the Array#sort method.

["Bob", "Mary", "Alice"].sort(function (a, b) {
    if (a < b) return 1;
    if (b < a) return -1;
    return 0;
});

Or if you don't want the original array modified, clone it first:

_.clone(["Bob", "Mary", "Alice"]).sort(...)

1 Comment

it worked for me when I reversed less than signs to greater than
0

Obviously you should not do this, as it makes far more sense to sort, then reverse the results, but if you really want to sort in reverse order inside the sort function, you could do something like this...

_.sortBy(["Bob", "Mary", "Alice"], function (a) {
    // split each string into single characters
    // ... then swap for inverse character from unicode range
    // ... and glue the characters back together into an inversely sortable string
    return _.map(a.split(''), function(i){
        return String.fromCharCode(65536 - i.charCodeAt(0));
    }).join('');
});

... also worth noting that underscore is subtly different than native javascript sort which has a small cross platform issue regarding consistent sort order...

If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this. Array.prototype.sort()

Underscore's .sortBy documentation states:

Returns a (stably) sorted copy of list. _.sortBy

Which it does by instead of returning 0 to keep items in order, it returns the index of the left side minus the index of the right side.

_.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');
};

Comments

0

You can do this with a 1 liner in ES6, just change the > depending on the direction you want.

.sort() is supported since IE6 and you just pass a function which returns 1 or -1;

["Bob", "Mary", "Alice].sort((a, b) => a > b ? 1 : -1);

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.