mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Add _.sortByMultiple.
This commit is contained in:
120
lodash.js
120
lodash.js
@@ -528,6 +528,26 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.sortBy` and `_.sortByMultiple` which uses
|
||||
* `comparer` to define the sort order of `array` and replaces criteria objects
|
||||
* with their corresponding values.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to sort.
|
||||
* @param {Function} comparer The function to define sort order.
|
||||
* @returns {Array} Returns `array`.
|
||||
*/
|
||||
function baseSortBy(array, comparer) {
|
||||
var length = array.length;
|
||||
|
||||
array.sort(comparer);
|
||||
while (length--) {
|
||||
array[length] = array[length].value;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `_.max` and `_.min` as the default callback for string values.
|
||||
*
|
||||
@@ -586,8 +606,8 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `_.sortBy` to compare multiple properties of each element in a
|
||||
* collection and stable sort them in ascending order.
|
||||
* Used by `_.sortByMultiple` to compare multiple properties of each element
|
||||
* in a collection and stable sort them in ascending order.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to compare to `other`.
|
||||
@@ -1000,10 +1020,10 @@
|
||||
* `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
|
||||
* `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
|
||||
* `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
|
||||
* `sortBy`, `splice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`,
|
||||
* `tap`, `throttle`, `thru`, `times`, `toArray`, `transform`, `union`, `uniq`,
|
||||
* `unshift`, `unzip`, `values`, `valuesIn`, `where`, `without`, `wrap`, `xor`,
|
||||
* `zip`, and `zipObject`
|
||||
* `sortBy`, `sortByMultiple`, `splice`, `take`, `takeRight`, `takeRightWhile`,
|
||||
* `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `transform`,
|
||||
* `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`, `where`,
|
||||
* `without`, `wrap`, `xor`, `zip`, and `zipObject`
|
||||
*
|
||||
* The non-chainable wrapper functions are:
|
||||
* `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
|
||||
@@ -6020,9 +6040,6 @@
|
||||
* If a property name is provided for `iteratee` the created "_.pluck" style
|
||||
* callback returns the property value of the given element.
|
||||
*
|
||||
* If an array of property names is provided for `iteratee` the collection
|
||||
* is sorted by each property value.
|
||||
*
|
||||
* If an object is provided for `iteratee` the created "_.where" style callback
|
||||
* returns `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
@@ -6032,8 +6049,8 @@
|
||||
* @category Collection
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Array|Function|Object|string} [iteratee=_.identity] The function
|
||||
* invoked per iteration. If property name(s) or an object is provided it
|
||||
* is used to create a "_.pluck" or "_.where" style callback respectively.
|
||||
* invoked per iteration. If a property name or an object is provided it is
|
||||
* used to create a "_.pluck" or "_.where" style callback respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `iteratee`.
|
||||
* @returns {Array} Returns the new sorted array.
|
||||
* @example
|
||||
@@ -6045,52 +6062,74 @@
|
||||
* // => [3, 1, 2]
|
||||
*
|
||||
* var users = [
|
||||
* { 'user': 'barney', 'age': 36 },
|
||||
* { 'user': 'fred', 'age': 40 },
|
||||
* { 'user': 'barney', 'age': 26 },
|
||||
* { 'user': 'fred', 'age': 30 }
|
||||
* { 'user': 'fred' },
|
||||
* { 'user': 'pebbles' },
|
||||
* { 'user': 'barney' }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.map(_.sortBy(users, 'age'), _.values);
|
||||
* // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
|
||||
*
|
||||
* // sorting by multiple properties
|
||||
* _.map(_.sortBy(users, ['user', 'age']), _.values);
|
||||
* // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
|
||||
* _.pluck(_.sortBy(users, 'user'), 'user');
|
||||
* // => ['barney', 'fred', 'pebbles']
|
||||
*/
|
||||
function sortBy(collection, iteratee, thisArg) {
|
||||
if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
|
||||
iteratee = null;
|
||||
}
|
||||
iteratee = getCallback(iteratee, thisArg, 3);
|
||||
|
||||
var index = -1,
|
||||
length = collection ? collection.length : 0,
|
||||
multi = iteratee && isArray(iteratee),
|
||||
result = isLength(length) ? Array(length) : [];
|
||||
|
||||
if (!multi) {
|
||||
iteratee = getCallback(iteratee, thisArg, 3);
|
||||
}
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
if (multi) {
|
||||
var length = iteratee.length,
|
||||
criteria = Array(length);
|
||||
result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
|
||||
});
|
||||
return baseSortBy(result, compareAscending);
|
||||
}
|
||||
|
||||
while (length--) {
|
||||
criteria[length] = value == null ? undefined : value[iteratee[length]];
|
||||
}
|
||||
} else {
|
||||
criteria = iteratee(value, key, collection);
|
||||
/**
|
||||
* This method is like `_.sortBy` except that it sorts by property names
|
||||
* instead of an iteratee function.
|
||||
*
|
||||
* @static
|
||||
* @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.
|
||||
* @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 }
|
||||
* ];
|
||||
*
|
||||
* _.map(_.sortBy(users, ['user', 'age']), _.values);
|
||||
* // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
|
||||
*/
|
||||
function sortByMultiple(collection) {
|
||||
var args = arguments;
|
||||
if (args.length == 4 && isIterateeCall(args[1], args[2], args[3])) {
|
||||
args = [collection, args[1]];
|
||||
}
|
||||
var index = -1,
|
||||
length = collection ? collection.length : 0,
|
||||
props = baseFlatten(args, false, false, 1),
|
||||
result = isLength(length) ? Array(length) : [];
|
||||
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
var length = props.length,
|
||||
criteria = Array(length);
|
||||
|
||||
while (length--) {
|
||||
criteria[length] = value == null ? undefined : value[props[length]];
|
||||
}
|
||||
result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
|
||||
});
|
||||
|
||||
length = result.length;
|
||||
result.sort(multi ? compareMultipleAscending : compareAscending);
|
||||
while (length--) {
|
||||
result[length] = result[length].value;
|
||||
}
|
||||
return result;
|
||||
return baseSortBy(result, compareMultipleAscending);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -9965,6 +10004,7 @@
|
||||
lodash.shuffle = shuffle;
|
||||
lodash.slice = slice;
|
||||
lodash.sortBy = sortBy;
|
||||
lodash.sortByMultiple = sortByMultiple;
|
||||
lodash.take = take;
|
||||
lodash.takeRight = takeRight;
|
||||
lodash.takeRightWhile = takeRightWhile;
|
||||
|
||||
87
test/test.js
87
test/test.js
@@ -10712,8 +10712,8 @@
|
||||
});
|
||||
|
||||
test('should work with a "_.pluck" style `iteratee`', 1, function() {
|
||||
var actual = _.pluck(_.sortBy(objects, 'b'), 'b');
|
||||
deepEqual(actual, [1, 2, 3, 4]);
|
||||
var actual = _.pluck(_.sortBy(objects.concat(undefined), 'b'), 'b');
|
||||
deepEqual(actual, [1, 2, 3, 4, undefined]);
|
||||
});
|
||||
|
||||
test('should work with an object for `collection`', 1, function() {
|
||||
@@ -10728,21 +10728,6 @@
|
||||
deepEqual(_.sortBy(1), []);
|
||||
});
|
||||
|
||||
test('should support sorting by an array of properties', 1, function() {
|
||||
var actual = _.sortBy(objects, ['a', 'b']);
|
||||
deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]);
|
||||
});
|
||||
|
||||
test('should not error on nullish elements when sorting by multiple properties', 1, function() {
|
||||
var actual = _.sortBy(objects.concat(undefined), ['a', 'b']);
|
||||
deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], undefined]);
|
||||
});
|
||||
|
||||
test('should perform a stable sort when sorting by multiple properties (test in IE > 8, Opera, and V8)', 1, function() {
|
||||
var actual = _.sortBy(stableOrder, ['a', 'c']);
|
||||
deepEqual(actual, stableOrder);
|
||||
});
|
||||
|
||||
test('should coerce arrays returned from `iteratee`', 1, function() {
|
||||
var actual = _.sortBy(objects, function(object) {
|
||||
var result = [object.a, object.b];
|
||||
@@ -10754,15 +10739,72 @@
|
||||
});
|
||||
|
||||
test('should work as an iteratee for `_.map`', 1, function() {
|
||||
var array = [[2, 1, 3], [3, 2, 1]],
|
||||
actual = _.map(array, _.sortBy);
|
||||
|
||||
var actual = _.map([[2, 1, 3], [3, 2, 1]], _.sortBy);
|
||||
deepEqual(actual, [[1, 2, 3], [1, 2, 3]]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.sortByMultiple');
|
||||
|
||||
(function() {
|
||||
function Pair(a, b, c) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
var objects = [
|
||||
{ 'a': 'x', 'b': 3 },
|
||||
{ 'a': 'y', 'b': 4 },
|
||||
{ 'a': 'x', 'b': 1 },
|
||||
{ 'a': 'y', 'b': 2 }
|
||||
];
|
||||
|
||||
var stableOrder = [
|
||||
new Pair(1, 1, 1), new Pair(1, 2, 1),
|
||||
new Pair(1, 1, 1), new Pair(1, 2, 1),
|
||||
new Pair(1, 3, 1), new Pair(1, 4, 1),
|
||||
new Pair(1, 5, 1), new Pair(1, 6, 1),
|
||||
new Pair(2, 1, 2), new Pair(2, 2, 2),
|
||||
new Pair(2, 3, 2), new Pair(2, 4, 2),
|
||||
new Pair(2, 5, 2), new Pair(2, 6, 2),
|
||||
new Pair(undefined, 1, 1), new Pair(undefined, 2, 1),
|
||||
new Pair(undefined, 3, 1), new Pair(undefined, 4, 1),
|
||||
new Pair(undefined, 5, 1), new Pair(undefined, 6, 1)
|
||||
];
|
||||
|
||||
test('should sort mutliple properties in ascending order', 1, function() {
|
||||
var actual = _.sortByMultiple(objects, ['a', 'b']);
|
||||
deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]);
|
||||
});
|
||||
|
||||
test('should perform a stable sort (test in IE > 8, Opera, and V8)', 1, function() {
|
||||
var actual = _.sortByMultiple(stableOrder, ['a', 'c']);
|
||||
deepEqual(actual, stableOrder);
|
||||
});
|
||||
|
||||
test('should not error on nullish elements', 1, function() {
|
||||
var actual = _.sortByMultiple(objects.concat(undefined), ['a', 'b']);
|
||||
deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], undefined]);
|
||||
});
|
||||
|
||||
test('should work as an iteratee for `_.reduce`', 1, function() {
|
||||
var objects = [
|
||||
{ 'a': 'x', '0': 3 },
|
||||
{ 'a': 'y', '0': 4 },
|
||||
{ 'a': 'x', '0': 1 },
|
||||
{ 'a': 'y', '0': 2 }
|
||||
];
|
||||
|
||||
var actual = _.reduce([['a']], _.sortByMultiple, objects);
|
||||
deepEqual(actual, [objects[0], objects[2], objects[1], objects[3]]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.sortedIndex');
|
||||
|
||||
(function() {
|
||||
@@ -13409,6 +13451,7 @@
|
||||
'sample',
|
||||
'shuffle',
|
||||
'sortBy',
|
||||
'sortByMultiple',
|
||||
'take',
|
||||
'times',
|
||||
'toArray',
|
||||
@@ -13447,7 +13490,7 @@
|
||||
|
||||
var acceptFalsey = _.difference(allMethods, rejectFalsey);
|
||||
|
||||
test('should accept falsey arguments', 200, function() {
|
||||
test('should accept falsey arguments', 202, function() {
|
||||
var emptyArrays = _.map(falsey, _.constant([])),
|
||||
isExposed = '_' in root,
|
||||
oldDash = root._;
|
||||
@@ -13489,7 +13532,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
test('should return an array', 68, function() {
|
||||
test('should return an array', 70, function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
_.each(returnArrays, function(methodName) {
|
||||
|
||||
Reference in New Issue
Block a user