Using Javascript with Underscore.js to Sort the ot

2020-05-19 04:38发布

问题:

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.

回答1:

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(...)


回答2:

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


回答3:

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


回答4:

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