Optimize _.reduce and _.reduceRight.

Former-commit-id: 6f281aae7f285458feafb02957fcd90fb09c10bd
This commit is contained in:
John-David Dalton
2012-12-06 23:28:12 -08:00
parent 090fb09955
commit cdeb50132d
2 changed files with 36 additions and 11 deletions

View File

@@ -135,7 +135,7 @@
'pluck': ['map'], 'pluck': ['map'],
'random': [], 'random': [],
'range': [], 'range': [],
'reduce': ['forEach'], 'reduce': ['forEach', 'isArray'],
'reduceRight': ['forEach', 'isString', 'keys'], 'reduceRight': ['forEach', 'isString', 'keys'],
'reject': ['filter'], 'reject': ['filter'],
'rest': [], 'rest': [],

View File

@@ -611,9 +611,11 @@
* @param {Function|String} [func=identity|property] The function called per * @param {Function|String} [func=identity|property] The function called per
* iteration or property name to query. * iteration or property name to query.
* @param {Mixed} [thisArg] The `this` binding of `callback`. * @param {Mixed} [thisArg] The `this` binding of `callback`.
* @param {Boolean} [accumulating] A flag to indicate creating a callback
* that accepts an `accumulator` argument.
* @returns {Function} Returns a callback function. * @returns {Function} Returns a callback function.
*/ */
function createCallback(func, thisArg) { function createCallback(func, thisArg, accumulating) {
if (!func) { if (!func) {
return identity; return identity;
} }
@@ -623,6 +625,11 @@
}; };
} }
if (typeof thisArg != 'undefined') { if (typeof thisArg != 'undefined') {
if (accumulating) {
return function(accumulator, value, index, object) {
return func.call(thisArg, accumulator, value, index, object);
};
}
return function(value, index, object) { return function(value, index, object) {
return func.call(thisArg, value, index, object); return func.call(thisArg, value, index, object);
}; };
@@ -1951,6 +1958,7 @@
function countBy(collection, callback, thisArg) { function countBy(collection, callback, thisArg) {
var result = {}; var result = {};
callback = createCallback(callback, thisArg); callback = createCallback(callback, thisArg);
forEach(collection, function(value, key, collection) { forEach(collection, function(value, key, collection) {
key = callback(value, key, collection); key = callback(value, key, collection);
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
@@ -2063,6 +2071,7 @@
function find(collection, callback, thisArg) { function find(collection, callback, thisArg) {
var result; var result;
callback = createCallback(callback, thisArg); callback = createCallback(callback, thisArg);
forEach(collection, function(value, index, collection) { forEach(collection, function(value, index, collection) {
if (callback(value, index, collection)) { if (callback(value, index, collection)) {
result = value; result = value;
@@ -2125,6 +2134,7 @@
function groupBy(collection, callback, thisArg) { function groupBy(collection, callback, thisArg) {
var result = {}; var result = {};
callback = createCallback(callback, thisArg); callback = createCallback(callback, thisArg);
forEach(collection, function(value, key, collection) { forEach(collection, function(value, key, collection) {
key = callback(value, key, collection); key = callback(value, key, collection);
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
@@ -2349,12 +2359,25 @@
*/ */
function reduce(collection, callback, accumulator, thisArg) { function reduce(collection, callback, accumulator, thisArg) {
var noaccum = arguments.length < 3; var noaccum = arguments.length < 3;
callback || (callback = identity); callback = createCallback(callback, thisArg, true);
forEach(collection, function(value, index, collection) {
accumulator = noaccum if (isArray(collection)) {
? (noaccum = false, value) var index = -1,
: callback.call(thisArg, accumulator, value, index, collection) length = collection.length;
});
if (noaccum) {
accumulator = collection[++index];
}
while (++index < length) {
accumulator = callback(accumulator, collection[index], index, collection);
}
} else {
forEach(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, value)
: callback(accumulator, value, index, collection)
});
}
return accumulator; return accumulator;
} }
@@ -2387,12 +2410,12 @@
} else if (noCharByIndex && isString(collection)) { } else if (noCharByIndex && isString(collection)) {
iteratee = collection.split(''); iteratee = collection.split('');
} }
callback || (callback = identity); callback = createCallback(callback, thisArg, true);
forEach(collection, function(value, index, collection) { forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length; index = props ? props[--length] : --length;
accumulator = noaccum accumulator = noaccum
? (noaccum = false, iteratee[index]) ? (noaccum = false, iteratee[index])
: callback.call(thisArg, accumulator, iteratee[index], index, collection); : callback(accumulator, iteratee[index], index, collection);
}); });
return accumulator; return accumulator;
} }
@@ -2541,6 +2564,7 @@
function sortBy(collection, callback, thisArg) { function sortBy(collection, callback, thisArg) {
var result = []; var result = [];
callback = createCallback(callback, thisArg); callback = createCallback(callback, thisArg);
forEach(collection, function(value, index, collection) { forEach(collection, function(value, index, collection) {
result.push({ result.push({
'criteria': callback(value, index, collection), 'criteria': callback(value, index, collection),
@@ -3051,9 +3075,10 @@
var low = 0, var low = 0,
high = array ? array.length : low; high = array ? array.length : low;
// explicitly reference `identity` for better engine inlining // explicitly reference `identity` for better inlining in Firefox
callback = callback ? createCallback(callback, thisArg) : identity; callback = callback ? createCallback(callback, thisArg) : identity;
value = callback(value); value = callback(value);
while (low < high) { while (low < high) {
var mid = (low + high) >>> 1; var mid = (low + high) >>> 1;
callback(array[mid]) < value callback(array[mid]) < value