From 04d6e351a645389e0c3001492104f83904f9ee6f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 10 May 2016 20:11:52 -0700 Subject: [PATCH] Add `fromIndex` param to `_.findIndex` and `_.findLastIndex`. --- lodash.js | 54 ++++++++++++++++++++++----------- test/test.js | 84 +++++++++++++++++++++++++++------------------------- 2 files changed, 80 insertions(+), 58 deletions(-) diff --git a/lodash.js b/lodash.js index fe9e41e6a..4e3fc37a8 100644 --- a/lodash.js +++ b/lodash.js @@ -717,12 +717,13 @@ * @private * @param {Array} array The array to search. * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {number} Returns the index of the matched value, else `-1`. */ - function baseFindIndex(array, predicate, fromRight) { + function baseFindIndex(array, predicate, fromIndex, fromRight) { var length = array.length, - index = fromRight ? length : -1; + index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { @@ -1040,7 +1041,7 @@ */ function indexOfNaN(array, fromIndex, fromRight) { var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); + index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { var other = array[index]; @@ -6428,6 +6429,7 @@ * @param {Array} array The array to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -6452,10 +6454,16 @@ * _.findIndex(users, 'active'); * // => 2 */ - function findIndex(array, predicate) { - return (array && array.length) - ? baseFindIndex(array, getIteratee(predicate, 3)) - : -1; + function findIndex(array, predicate, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); } /** @@ -6469,6 +6477,7 @@ * @param {Array} array The array to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -6493,10 +6502,19 @@ * _.findLastIndex(users, 'active'); * // => 0 */ - function findLastIndex(array, predicate) { - return (array && array.length) - ? baseFindIndex(array, getIteratee(predicate, 3), true) - : -1; + function findLastIndex(array, predicate, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); } /** @@ -6643,11 +6661,11 @@ if (!length) { return -1; } - fromIndex = toInteger(fromIndex); - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); } - return baseIndexOf(array, value, fromIndex); + return baseIndexOf(array, value, index); } /** @@ -6838,7 +6856,7 @@ ) + 1; } if (value !== value) { - return indexOfNaN(array, index, true); + return indexOfNaN(array, index - 1, true); } while (index--) { if (array[index] === value) { @@ -8414,7 +8432,7 @@ function find(collection, predicate) { predicate = getIteratee(predicate, 3); if (isArray(collection)) { - var index = baseFindIndex(collection, predicate); + var index = baseFindIndex(collection, predicate, 0); return index > -1 ? collection[index] : undefined; } return baseFind(collection, predicate, baseEach); @@ -8442,7 +8460,7 @@ function findLast(collection, predicate) { predicate = getIteratee(predicate, 3); if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, true); + var index = baseFindIndex(collection, predicate, collection.length - 1, true); return index > -1 ? collection[index] : undefined; } return baseFind(collection, predicate, baseEachRight); diff --git a/test/test.js b/test/test.js index 30187c03c..1d9055590 100644 --- a/test/test.js +++ b/test/test.js @@ -7768,24 +7768,26 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.indexOf'); + QUnit.module('lodash.findIndex and lodash.indexOf'); - (function() { - var array = [1, 2, 3, 1, 2, 3]; + lodashStable.each(['findIndex', 'indexOf'], function(methodName) { + var array = [1, 2, 3, 1, 2, 3], + func = _[methodName], + resolve = methodName == 'findIndex' ? lodashStable.curry(lodashStable.eq) : identity; - QUnit.test('should return the index of the first matched value', function(assert) { + QUnit.test('`_.' + methodName + '` should return the index of the first matched value', function(assert) { assert.expect(1); - assert.strictEqual(_.indexOf(array, 3), 2); + assert.strictEqual(func(array, resolve(3)), 2); }); - QUnit.test('should work with a positive `fromIndex`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a positive `fromIndex`', function(assert) { assert.expect(1); - assert.strictEqual(_.indexOf(array, 1, 2), 3); + assert.strictEqual(func(array, resolve(1), 2), 3); }); - QUnit.test('should work with `fromIndex` >= `array.length`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with `fromIndex` >= `array.length`', function(assert) { assert.expect(1); var values = [6, 8, Math.pow(2, 32), Infinity], @@ -7793,52 +7795,52 @@ var actual = lodashStable.map(values, function(fromIndex) { return [ - _.indexOf(array, undefined, fromIndex), - _.indexOf(array, 1, fromIndex), - _.indexOf(array, '', fromIndex) + func(array, resolve(undefined), fromIndex), + func(array, resolve(1), fromIndex), + func(array, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); - QUnit.test('should work with a negative `fromIndex`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex`', function(assert) { assert.expect(1); - assert.strictEqual(_.indexOf(array, 2, -3), 4); + assert.strictEqual(func(array, resolve(2), -3), 4); }); - QUnit.test('should work with a negative `fromIndex` <= `-array.length`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex` <= `-array.length`', function(assert) { assert.expect(1); var values = [-6, -8, -Infinity], expected = lodashStable.map(values, alwaysZero); var actual = lodashStable.map(values, function(fromIndex) { - return _.indexOf(array, 1, fromIndex); + return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); - QUnit.test('should treat falsey `fromIndex` values as `0`', function(assert) { + QUnit.test('`_.' + methodName + '` should treat falsey `fromIndex` values as `0`', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, alwaysZero); var actual = lodashStable.map(falsey, function(fromIndex) { - return _.indexOf(array, 1, fromIndex); + return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); - QUnit.test('should coerce `fromIndex` to an integer', function(assert) { + QUnit.test('`_.' + methodName + '` should coerce `fromIndex` to an integer', function(assert) { assert.expect(1); - assert.strictEqual(_.indexOf(array, 2, 1.2), 1); + assert.strictEqual(func(array, resolve(2), 1.2), 1); }); - }()); + }); /*--------------------------------------------------------------------------*/ @@ -13114,24 +13116,26 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.lastIndexOf'); + QUnit.module('lodash.findLastIndex and lodash.lastIndexOf'); - (function() { - var array = [1, 2, 3, 1, 2, 3]; + lodashStable.each(['findLastIndex', 'lastIndexOf'], function(methodName) { + var array = [1, 2, 3, 1, 2, 3], + func = _[methodName], + resolve = methodName == 'findLastIndex' ? lodashStable.curry(lodashStable.eq) : identity; - QUnit.test('should return the index of the last matched value', function(assert) { + QUnit.test('`_.' + methodName + '` should return the index of the last matched value', function(assert) { assert.expect(1); - assert.strictEqual(_.lastIndexOf(array, 3), 5); + assert.strictEqual(func(array, resolve(3)), 5); }); - QUnit.test('should work with a positive `fromIndex`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a positive `fromIndex`', function(assert) { assert.expect(1); - assert.strictEqual(_.lastIndexOf(array, 1, 2), 0); + assert.strictEqual(func(array, resolve(1), 2), 0); }); - QUnit.test('should work with `fromIndex` >= `array.length`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with `fromIndex` >= `array.length`', function(assert) { assert.expect(1); var values = [6, 8, Math.pow(2, 32), Infinity], @@ -13139,35 +13143,35 @@ var actual = lodashStable.map(values, function(fromIndex) { return [ - _.lastIndexOf(array, undefined, fromIndex), - _.lastIndexOf(array, 1, fromIndex), - _.lastIndexOf(array, '', fromIndex) + func(array, resolve(undefined), fromIndex), + func(array, resolve(1), fromIndex), + func(array, resolve(''), fromIndex) ]; }); assert.deepEqual(actual, expected); }); - QUnit.test('should work with a negative `fromIndex`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex`', function(assert) { assert.expect(1); - assert.strictEqual(_.lastIndexOf(array, 2, -3), 1); + assert.strictEqual(func(array, resolve(2), -3), 1); }); - QUnit.test('should work with a negative `fromIndex` <= `-array.length`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a negative `fromIndex` <= `-array.length`', function(assert) { assert.expect(1); var values = [-6, -8, -Infinity], expected = lodashStable.map(values, alwaysZero); var actual = lodashStable.map(values, function(fromIndex) { - return _.lastIndexOf(array, 1, fromIndex); + return func(array, resolve(1), fromIndex); }); assert.deepEqual(actual, expected); }); - QUnit.test('should treat falsey `fromIndex` values correctly', function(assert) { + QUnit.test('`_.' + methodName + '` should treat falsey `fromIndex` values correctly', function(assert) { assert.expect(1); var expected = lodashStable.map(falsey, function(value) { @@ -13175,18 +13179,18 @@ }); var actual = lodashStable.map(falsey, function(fromIndex) { - return _.lastIndexOf(array, 3, fromIndex); + return func(array, resolve(3), fromIndex); }); assert.deepEqual(actual, expected); }); - QUnit.test('should coerce `fromIndex` to an integer', function(assert) { + QUnit.test('`_.' + methodName + '` should coerce `fromIndex` to an integer', function(assert) { assert.expect(1); - assert.strictEqual(_.lastIndexOf(array, 2, 4.2), 4); + assert.strictEqual(func(array, resolve(2), 4.2), 4); }); - }()); + }); /*--------------------------------------------------------------------------*/