Move _.pluck and _.invoke back to the "Collections" category and optimize _.sortedIndex when a callback is passed.

Former-commit-id: d16763e7d35660d8ba9ea976c8b2a4dc20f1211f
This commit is contained in:
John-David Dalton
2012-06-14 00:28:36 -04:00
parent e5555dd26a
commit 24c9b6e211
3 changed files with 112 additions and 89 deletions

View File

@@ -8,6 +8,7 @@
/** Used to minify variables embedded in compiled strings */
var compiledVars = [
'accumulator',
'args',
'arrayClass',
'callback',
'className',
@@ -18,14 +19,17 @@
'hasOwnProperty',
'identity',
'index',
'isFunc',
'iteratorBind',
'length',
'methodName',
'noaccum',
'object',
'objectTypes',
'noaccum',
'property',
'result',
'skipProto',
'slice',
'source',
'sourceIndex',
'stringClass',

169
lodash.js
View File

@@ -339,6 +339,20 @@
}
};
/** Reusable iterator options for `invoke`, `map`, and `pluck` */
var mapIteratorOptions = {
'init': '',
'exit': 'if (!collection) return []',
'beforeLoop': {
'array': 'result = Array(length)',
'object': 'result = []'
},
'inLoop': {
'array': 'result[index] = callback(collection[index], index, collection)',
'object': 'result.push(callback(collection[index], index, collection))'
}
};
/*--------------------------------------------------------------------------*/
/**
@@ -437,13 +451,13 @@
// create the function factory
var factory = Function(
'arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes, ' +
'stringClass, toString, undefined',
'slice, stringClass, toString, undefined',
'"use strict"; return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
);
// return the compiled function
return factory(
arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes,
stringClass, toString
slice, stringClass, toString
);
}
@@ -679,7 +693,40 @@
var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);
/**
* Produces a new array of values by mapping each value in the `collection`
* Invokes the method named by `methodName` on each element in the `collection`.
* Additional arguments will be passed to each invoked method. If `methodName`
* is a function it will be invoked for, and `this` bound to, each element
* in the `collection`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
* @param {Function|String} methodName The name of the method to invoke or
* the function invoked per iteration.
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
* @returns {Array} Returns a new array of values returned from each invoked method.
* @example
*
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
* // => [[1, 5, 7], [1, 2, 3]]
*
* _.invoke([123, 456], String.prototype.split, '');
* // => [['1', '2', '3'], ['4', '5', '6']]
*/
var invoke = createIterator(mapIteratorOptions, {
'args': 'collection, methodName',
'top':
'var args = slice.call(arguments, 2),\n' +
' isFunc = typeof methodName == \'function\'',
'inLoop': {
'array': 'result[index] = (isFunc ? methodName : collection[index][methodName]).apply(collection[index], args)',
'object': 'result.push((isFunc ? methodName : collection[index][methodName]).apply(collection[index], args))'
}
});
/**
* Produces a new array of values by mapping each element in the `collection`
* through a transformation `callback`. The `callback` is bound to `thisArg`
* and invoked with 3 arguments; for arrays they are (value, index, array)
* and for objects they are (value, key, object).
@@ -700,16 +747,34 @@
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
* // => [3, 6, 9] (order is not guaranteed)
*/
var map = createIterator(baseIteratorOptions, {
'init': '',
'exit': 'if (!collection) return []',
'beforeLoop': {
'array': 'result = Array(length)',
'object': 'result = []'
},
var map = createIterator(baseIteratorOptions, mapIteratorOptions);
/**
* Retrieves the value of a specified property from all elements in
* the `collection`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
* @param {String} property The property to pluck.
* @returns {Array} Returns a new array of property values.
* @example
*
* var stooges = [
* { 'name': 'moe', 'age': 40 },
* { 'name': 'larry', 'age': 50 },
* { 'name': 'curly', 'age': 60 }
* ];
*
* _.pluck(stooges, 'name');
* // => ['moe', 'larry', 'curly']
*/
var pluck = createIterator(mapIteratorOptions, {
'args': 'collection, property',
'inLoop': {
'array': 'result[index] = callback(collection[index], index, collection)',
'object': 'result.push(callback(collection[index], index, collection))'
'array': 'result[index] = collection[index][property]',
'object': 'result.push(collection[index][property])'
}
});
@@ -1159,44 +1224,6 @@
return result;
}
/**
* Invokes the method named by `methodName` on each element of `array`.
* Additional arguments will be passed to each invoked method. If `methodName`
* is a function it will be invoked for, and `this` bound to, each element
* of `array`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
* @param {Function|String} methodName The name of the method to invoke or
* the function invoked per iteration.
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
* @returns {Array} Returns a new array of values returned from each invoked method.
* @example
*
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
* // => [[1, 5, 7], [1, 2, 3]]
*
* _.invoke([123, 456], String.prototype.split, '');
* // => [['1', '2', '3'], ['4', '5', '6']]
*/
function invoke(array, methodName) {
var result = [];
if (!array) {
return result;
}
var args = slice.call(arguments, 2),
index = -1,
length = array.length,
isFunc = typeof methodName == 'function';
while (++index < length) {
result[index] = (isFunc ? methodName : array[index][methodName]).apply(array[index], args);
}
return result;
}
/**
* Gets the last value of the `array`. Pass `n` to return the lasy `n` values
* of the `array`.
@@ -1363,40 +1390,6 @@
return result;
}
/**
* Retrieves the value of a specified property from all elements in `array`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
* @param {String} property The property to pluck.
* @returns {Array} Returns a new array of property values.
* @example
*
* var stooges = [
* { 'name': 'moe', 'age': 40 },
* { 'name': 'larry', 'age': 50 },
* { 'name': 'curly', 'age': 60 }
* ];
*
* _.pluck(stooges, 'name');
* // => ['moe', 'larry', 'curly']
*/
function pluck(array, property) {
if (!array) {
return [];
}
var index = -1,
length = array.length,
result = Array(length);
while (++index < length) {
result[index] = array[index][property];
}
return result;
}
/**
* Creates an array of numbers (positive and/or negative) progressing from
* `start` up to but not including `stop`. This method is a port of Python's
@@ -1608,10 +1601,14 @@
high = array.length;
if (callback) {
value = callback.call(thisArg, value);
if (thisArg) {
var fn = callback;
callback = function(value) { return fn.call(thisArg, value); };
}
value = callback(value);
while (low < high) {
mid = (low + high) >>> 1;
callback.call(thisArg, array[mid]) < value ? low = mid + 1 : high = mid;
callback(array[mid]) < value ? low = mid + 1 : high = mid;
}
} else {
while (low < high) {

View File

@@ -378,6 +378,17 @@
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.invoke');
(function() {
test('should work with an object for `collection`', function() {
var object = { 'a': 1, 'b': 2, 'c': 3 };
deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isEmpty');
(function() {
@@ -520,6 +531,17 @@
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.pluck');
(function() {
test('should work with an object for `collection`', function() {
var object = { 'a': [1], 'b': [1, 2], 'c': [1, 2, 3] };
deepEqual(_.pluck(object, 'length'), [1, 2, 3]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.reduceRight');
(function() {
@@ -743,12 +765,10 @@
'indexOf',
'initial',
'intersection',
'invoke',
'last',
'lastIndexOf',
'max',
'min',
'pluck',
'range',
'rest',
'shuffle',
@@ -782,7 +802,9 @@
'filter',
'find',
'forEach',
'invoke',
'map',
'pluck',
'reduce',
'reduceRight',
'reject',