Add _.forEachRight, _.forInRight, _.forOwnRight, _.findLast, _.findLastIndex, and _.findLastKey methods. [closes #309]

Former-commit-id: 7097f79e278bf2dfacfed449ce5f64a2dc19a662
This commit is contained in:
John-David Dalton
2013-07-27 00:21:23 -07:00
parent 4398fca1bd
commit 0404776d87
4 changed files with 276 additions and 36 deletions

View File

@@ -115,12 +115,18 @@
'filter': ['baseEach', 'createCallback', 'isArray'],
'find': ['baseEach', 'createCallback', 'isArray'],
'findIndex': ['createCallback'],
'findLastIndex': ['createCallback'],
'findKey': ['createCallback', 'forOwn'],
'findLast': ['createCallback', 'forEachRight'],
'findLastKey': ['createCallback', 'forOwnRight'],
'first': ['createCallback', 'slice'],
'flatten': ['baseFlatten', 'map'],
'forEach': ['baseEach', 'createCallback', 'isArray'],
'forEachRight': ['createCallback', 'forEach', 'isString', 'keys'],
'forIn': ['createIterator'],
'forInRight': ['createCallback', 'forIn'],
'forOwn': ['createIterator'],
'forOwnRight': ['createCallback', 'keys'],
'functions': ['forIn', 'isFunction'],
'groupBy': ['createAggregator'],
'has': [],
@@ -169,7 +175,7 @@
'random': [],
'range': [],
'reduce': ['baseEach', 'createCallback', 'isArray'],
'reduceRight': ['createCallback', 'forEach', 'isString', 'keys'],
'reduceRight': ['createCallback', 'forEachRight'],
'reject': ['createCallback', 'filter'],
'rest': ['createCallback', 'slice'],
'result': ['isFunction'],
@@ -295,6 +301,7 @@
'compact',
'difference',
'findIndex',
'findLastIndex',
'first',
'flatten',
'indexOf',
@@ -323,8 +330,10 @@
'every',
'filter',
'find',
'findLast',
'findWhere',
'forEach',
'forEachRight',
'groupBy',
'indexBy',
'invoke',
@@ -365,8 +374,11 @@
'cloneDeep',
'defaults',
'findKey',
'findLastKey',
'forIn',
'forInRight',
'forOwn',
'forOwnRight',
'functions',
'has',
'invert',
@@ -515,8 +527,14 @@
'createCallback',
'findIndex',
'findKey',
'findLast',
'findLastIndex',
'findLastKey',
'forEachRight',
'forIn',
'forInRight',
'forOwn',
'forOwnRight',
'indexBy',
'isPlainObject',
'merge',

View File

@@ -133,14 +133,20 @@
'find',
'findIndex',
'findKey',
'findLast',
'findLastIndex',
'findLastKey',
'findWhere',
'first',
'flatten',
'foldl',
'foldr',
'forEach',
'forEachRight',
'forIn',
'forInRight',
'forOwn',
'forOwnRight',
'function',
'functions',
'global',

274
lodash.js
View File

@@ -1931,7 +1931,7 @@
var defaults = createIterator(defaultsIteratorOptions);
/**
* This method is similar to `_.find`, except that it returns the key of the
* This method is like `_.findIndex`, except that it returns the key of the
* element that passes the callback check, instead of the element itself.
*
* @static
@@ -1948,7 +1948,7 @@
* _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
* return num % 2 == 0;
* });
* // => 'b'
* // => 'b' (order is not guaranteed)
*/
function findKey(object, callback, thisArg) {
var result;
@@ -1962,6 +1962,38 @@
return result;
}
/**
* This method is like `_.findKey`, except that it iterates over elements
* of a `collection` in the opposite order.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to search.
* @param {Function|Object|String} [callback=identity] The function called per
* iteration. If a property name or object is passed, it will be used to create
* a "_.pluck" or "_.where" style callback, respectively.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the key of the found element, else `undefined`.
* @example
*
* _.findLastKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
* return num % 2 == 1;
* });
* // => returns `c`, assuming `_.findKey` returns `a`
*/
function findLastKey(object, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg);
forOwnRight(object, function(value, key, object) {
if (callback(value, key, object)) {
result = key;
return false;
}
});
return result;
}
/**
* Iterates over own and inherited enumerable properties of a given `object`,
* executing the `callback` for each property. The `callback` is bound to
@@ -1983,18 +2015,62 @@
* }
*
* Dog.prototype.bark = function() {
* alert('Woof, woof!');
* console.log('Woof, woof!');
* };
*
* _.forIn(new Dog('Dagny'), function(value, key) {
* alert(key);
* console.log(key);
* });
* // => alerts 'name' and 'bark' (order is not guaranteed)
* // => logs 'bark' and 'name' (order is not guaranteed)
*/
var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
'useHas': false
});
/**
* This method is like `_.forIn`, except that it iterates over elements
* of a `collection` in the opposite order.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* function Dog(name) {
* this.name = name;
* }
*
* Dog.prototype.bark = function() {
* console.log('Woof, woof!');
* };
*
* _.forInRight(new Dog('Dagny'), function(value, key) {
* console.log(key);
* });
* // => logs 'name' and 'bark' assuming `_.forIn ` logs 'bark' and 'name'
*/
function forInRight(object, callback, thisArg) {
var index = -1,
pairs = [];
forIn(object, function(value, key) {
pairs.push(value, key);
});
var length = pairs.length;
callback = lodash.createCallback(callback, thisArg, 3);
while (++index < length) {
if (callback(pairs[index], pairs[++index], object) === false) {
break;
}
}
return object;
}
/**
* Iterates over own enumerable properties of a given `object`, executing the
* `callback` for each property. The `callback` is bound to `thisArg` and
@@ -2012,12 +2088,44 @@
* @example
*
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
* alert(key);
* console.log(key);
* });
* // => alerts '0', '1', and 'length' (order is not guaranteed)
* // => logs '0', '1', and 'length' (order is not guaranteed)
*/
var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
/**
* This method is like `_.forOwn`, except that it iterates over elements
* of a `collection` in the opposite order.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
* console.log(key);
* });
* // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
*/
function forOwnRight(object, callback, thisArg) {
var props = keys(object),
length = props.length;
callback = lodash.createCallback(callback, thisArg, 3);
while (length--) {
var key = props[length];
if (callback(object[key], key, object) === false) {
break;
}
}
return object;
}
/**
* Creates a sorted array of property names of all enumerable properties,
* own and inherited, of `object` that have function values.
@@ -3061,6 +3169,38 @@
}
}
/**
* This method is like `_.find`, except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
* @param {Function|Object|String} [callback=identity] The function called per
* iteration. If a property name or object is passed, it will be used to create
* a "_.pluck" or "_.where" style callback, respectively.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the found element, else `undefined`.
* @example
*
* _.findLast([1, 2, 3, 4], function(num) {
* return num % 2 == 1;
* });
* // => 3
*/
function findLast(collection, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg);
forEachRight(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result = value;
return false;
}
});
return result;
}
/**
* Iterates over elements of a `collection`, executing the `callback` for
* each element. The `callback` is bound to `thisArg` and invoked with three
@@ -3077,11 +3217,11 @@
* @returns {Array|Object|String} Returns `collection`.
* @example
*
* _([1, 2, 3]).forEach(alert).join(',');
* // => alerts each number and returns '1,2,3'
* _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
* // => logs each number and returns '1,2,3'
*
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
* // => alerts each number value (order is not guaranteed)
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
* // => logs each number value and returns the object (order is not guaranteed)
*/
function forEach(collection, callback, thisArg) {
if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
@@ -3099,6 +3239,41 @@
return collection;
}
/**
* This method is like `_.forEach`, except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @alias each
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|String} Returns `collection`.
* @example
*
* _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
* // => logs each number from right to left and returns '3,2,1'
*/
function forEachRight(collection, callback, thisArg) {
var iterable = collection,
length = collection ? collection.length : 0;
if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
}
callback = lodash.createCallback(callback, thisArg, 3);
forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length;
callback(iterable[index], index, collection);
});
return collection;
}
/**
* Creates an object composed of keys generated from the results of running
* each element of the `collection` through the `callback`. The corresponding
@@ -3488,7 +3663,7 @@
}
/**
* This method is similar to `_.reduce`, except that it iterates over elements
* This method is like `_.reduce`, except that it iterates over elements
* of a `collection` from right to left.
*
* @static
@@ -3507,22 +3682,12 @@
* // => [4, 5, 2, 3, 0, 1]
*/
function reduceRight(collection, callback, accumulator, thisArg) {
var iterable = collection,
length = collection ? collection.length : 0,
noaccum = arguments.length < 3;
if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
}
var noaccum = arguments.length < 3;
callback = lodash.createCallback(callback, thisArg, 4);
forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length;
forEachRight(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, iterable[index])
: callback(accumulator, iterable[index], index, collection);
? (noaccum = false, value)
: callback(accumulator, value, index, collection);
});
return accumulator;
}
@@ -3871,8 +4036,8 @@
}
/**
* This method is similar to `_.find`, except that it returns the index of
* the element that passes the callback check, instead of the element itself.
* This method is like `_.find`, except that it returns the index of the
* element that passes the callback check, instead of the element itself.
*
* @static
* @memberOf _
@@ -3903,6 +4068,39 @@
return -1;
}
/**
* This method is like `_.findIndex`, except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {Function|Object|String} [callback=identity] The function called per
* iteration. If a property name or object is passed, it will be used to create
* a "_.pluck" or "_.where" style callback, respectively.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the index of the found element, else `-1`.
* @example
*
* _.findLastIndex(['apple', 'banana', 'beet'], function(food) {
* return /^b/.test(food);
* });
* // => 2
*/
function findLastIndex(array, callback, thisArg) {
var index = -1,
length = array ? array.length : 0;
callback = lodash.createCallback(callback, thisArg);
while (length--) {
if (callback(array[index], index, array)) {
return index;
}
}
return -1;
}
/**
* Gets the first element of the `array`. If a number `n` is passed, the first
* `n` elements of the `array` are returned. If a `callback` function is passed,
@@ -4731,12 +4929,12 @@
*
* var view = {
* 'label': 'docs',
* 'onClick': function() { alert('clicked ' + this.label); }
* 'onClick': function() { console.log('clicked ' + this.label); }
* };
*
* _.bindAll(view);
* jQuery('#docs').on('click', view.onClick);
* // => alerts 'clicked docs', when the button is clicked
* // => logs 'clicked docs', when the button is clicked
*/
function bindAll(object) {
var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
@@ -5067,8 +5265,8 @@
* @returns {Number} Returns the timer id.
* @example
*
* _.defer(function() { alert('deferred'); });
* // returns from the function before `alert` is called
* _.defer(function() { console.log('deferred'); });
* // returns from the function before 'deferred' is logged
*/
function defer(func) {
var args = nativeSlice.call(arguments, 1);
@@ -5191,7 +5389,7 @@
}
/**
* This method is similar to `_.partial`, except that `partial` arguments are
* This method is like `_.partial`, except that `partial` arguments are
* appended to those passed to the new function.
*
* @static
@@ -5772,10 +5970,10 @@
*
* _([1, 2, 3, 4])
* .filter(function(num) { return num % 2 == 0; })
* .tap(alert)
* .tap(function(array) { console.log(array); })
* .map(function(num) { return num * num; })
* .value();
* // => // [2, 4] (alerted)
* // => // [2, 4] (logged)
* // => [4, 16]
*/
function tap(value, interceptor) {
@@ -5837,8 +6035,11 @@
lodash.filter = filter;
lodash.flatten = flatten;
lodash.forEach = forEach;
lodash.forEachRight = forEachRight;
lodash.forIn = forIn;
lodash.forInRight = forInRight;
lodash.forOwn = forOwn;
lodash.forOwnRight = forOwnRight;
lodash.functions = functions;
lodash.groupBy = groupBy;
lodash.indexBy = indexBy;
@@ -5907,7 +6108,10 @@
lodash.every = every;
lodash.find = find;
lodash.findIndex = findIndex;
lodash.findLast = findLast;
lodash.findLastIndex = findLastIndex;
lodash.findKey = findKey;
lodash.findLastKey = findLastKey;
lodash.has = has;
lodash.identity = identity;
lodash.indexOf = indexOf;

View File

@@ -97,6 +97,7 @@
'compact',
'difference',
'findIndex',
'findLastIndex',
'first',
'flatten',
'indexOf',
@@ -125,8 +126,10 @@
'every',
'filter',
'find',
'findLast',
'findWhere',
'forEach',
'forEachRight',
'groupBy',
'indexBy',
'invoke',
@@ -167,8 +170,11 @@
'cloneDeep',
'defaults',
'findKey',
'findLastKey',
'forIn',
'forInRight',
'forOwn',
'forOwnRight',
'functions',
'has',
'invert',
@@ -279,8 +285,14 @@
'createCallback',
'findIndex',
'findKey',
'findLast',
'findLastIndex',
'findLastKey',
'forEachRight',
'forIn',
'forInRight',
'forOwn',
'forOwnRight',
'indexBy',
'isPlainObject',
'merge',