From bc3771f3af83787cfe62b87162c840804ff64443 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Sun, 12 Apr 2015 13:01:52 -0400 Subject: [PATCH] Support iteratee use cases for `_.sortByAll` and `_.sortByOrder`. --- lodash.src.js | 48 +++++++++++++++++++++++++++--------------------- test/test.js | 16 ++++++++++++---- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index a0b2bbaf7..aecfae290 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2845,19 +2845,21 @@ * @param {boolean[]} orders The sort orders of `props`. * @returns {Array} Returns the new sorted array. */ - function baseSortByOrder(collection, props, orders) { - var index = -1, - length = getLength(collection), - result = isLength(length) ? Array(length) : []; + function baseSortByOrder(collection, comparators, orders) { + var callback = getCallback(); - baseEach(collection, function(value) { - var length = props.length, + comparators = arrayMap(comparators, function(comparitor) { + return callback(comparitor); + }); + + var result = baseMap(collection, function(value, index) { + var length = comparators.length, criteria = Array(length); while (length--) { - criteria[length] = value == null ? undefined : value[props[length]]; + criteria[length] = comparators[length](value); } - result[++index] = { 'criteria': criteria, 'index': index, 'value': value }; + return { 'criteria': criteria, 'index': index, 'value': value }; }); return baseSortBy(result, function(object, other) { @@ -7313,20 +7315,24 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(string|string[])} props The property names to sort by, - * specified as individual property names or arrays of property names. + * @param {...(string|string[]|func[])} args The iteratees to sort by, + * specified by a single, an array or multiple property names and functions. * @returns {Array} Returns the new sorted array. * @example * * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 26 }, - * { 'user': 'fred', 'age': 30 } + * { 'user': 'barney', 'age': 36, 'years': 1}, + * { 'user': 'fred', 'age': 40, 'years': 5}, + * { 'user': 'barney', 'age': 26, 'years': 0}, + * { 'user': 'fred', 'age': 30, 'years': 3} * ]; * * _.map(_.sortByAll(users, ['user', 'age']), _.values); - * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] + * // => [['barney', 26, 0], ['barney', 40, 6], ['fred', 30, 3], ['fred', 36, 1]] + * + * function a(customer) {return customer.age - customer.years} + * _.sortByAll(users, a, 'age') + * // => [['barney', 26, 0], ['fred', 30, 3], ['barney', 40, 6], ['fred', 36, 1]] */ var sortByAll = restParam(function(collection, args) { if (collection == null) { @@ -7349,7 +7355,7 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {string[]} props The property names to sort by. + * @param {string[]|func[]} comparators The iteratees to sort by. * @param {boolean[]} orders The sort orders of `props`. * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. * @returns {Array} Returns the new sorted array. @@ -7366,20 +7372,20 @@ * _.map(_.sortByOrder(users, ['user', 'age'], [true, false]), _.values); * // => [['barney', 36], ['barney', 26], ['fred', 40], ['fred', 30]] */ - function sortByOrder(collection, props, orders, guard) { + function sortByOrder(collection, comparators, orders, guard) { if (collection == null) { return []; } - if (guard && isIterateeCall(props, orders, guard)) { + if (guard && isIterateeCall(comparators, orders, guard)) { orders = null; } - if (!isArray(props)) { - props = props == null ? [] : [props]; + if (!isArray(comparators)) { + comparators = comparators == null ? [] : [comparators]; } if (!isArray(orders)) { orders = orders == null ? [] : [orders]; } - return baseSortByOrder(collection, props, orders); + return baseSortByOrder(collection, comparators, orders); } /** diff --git a/test/test.js b/test/test.js index 3c868d606..27f27d333 100644 --- a/test/test.js +++ b/test/test.js @@ -14185,10 +14185,10 @@ } var objects = [ - { 'a': 'x', 'b': 3 }, - { 'a': 'y', 'b': 4 }, - { 'a': 'x', 'b': 1 }, - { 'a': 'y', 'b': 2 } + { 'a': 'x', 'b': 3, c: 2 }, + { 'a': 'y', 'b': 4, c: 1 }, + { 'a': 'x', 'b': 1, c: 4}, + { 'a': 'y', 'b': 2, c: 3} ]; var stableOrder = [ @@ -14209,6 +14209,14 @@ deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); }); + test('`_.' + methodName + '` should permit function comparators', 1, function() { + function b(obj) { + return obj.b * obj.c; + } + var actual = func(objects, [b, 'a']); + deepEqual(actual, [objects[2], objects[1], objects[0], objects[3]]); + }); + test('`_.' + methodName + '` should perform a stable sort (test in IE > 8, Opera, and V8)', 1, function() { var actual = func(stableOrder, ['a', 'c']); deepEqual(actual, stableOrder);