From 3d8cc32302d3f2e4e1fa85c9b2f0c9ddd412ba73 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 31 May 2012 17:23:45 -0600 Subject: [PATCH] Add `fromIndex` to `_.indexOf` and `_.lastIndexOf`. [closes #20] Former-commit-id: 3ab67c318a5a7fc2e521a9a2573b694e6920b14d --- lodash.js | 57 ++++++++++++++++++++++++++++--------------- test/test.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 20 deletions(-) diff --git a/lodash.js b/lodash.js index 425d6e857..fef419915 100644 --- a/lodash.js +++ b/lodash.js @@ -1077,6 +1077,9 @@ * * _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return this.sin(num); }, Math); * // => [5, 4, 6, 3, 1, 2] + * + * _.sortBy(['larry', 'brendan', 'moe'], 'length'); + * // => ['moe', 'larry', 'brendan'] */ function sortBy(array, callback, thisArg) { if (toString.call(callback) != funcClass) { @@ -1114,23 +1117,33 @@ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. - * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. + * @param {Boolean|Number} [fromIndex=0] The index to start searching from or + * `true` to perform a binary search on a sorted `array`. * @returns {Number} Returns the index of the matched value or `-1`. * @example * - * _.indexOf([1, 2, 3], 2); + * _.indexOf([1, 2, 3, 1, 2, 3], 2); * // => 1 + * + * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 4 + * + * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); + * // => 2 */ - function indexOf(array, value, isSorted) { - var index, length; - if (!array) { - return -1; + function indexOf(array, value, fromIndex) { + var index = -1, + length = array.length; + + if (fromIndex) { + if (fromIndex === +fromIndex) { + index = (fromIndex < 0 ? Math.max(0, length + fromIndex) : fromIndex) - 1; + } else { + index = sortedIndex(array, value); + return array[index] === value ? index : -1; + } } - if (isSorted) { - index = sortedIndex(array, value); - return array[index] === value ? index : -1; - } - for (index = 0, length = array.length; index < length; index++) { + while (++index < length) { if (array[index] === value) { return index; } @@ -1250,17 +1263,21 @@ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=array.length-1] The index to start searching from. * @returns {Number} Returns the index of the matched value or `-1`. * @example * * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); * // => 4 + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 1 */ - function lastIndexOf(array, value) { - if (!array) { - return -1; - } + function lastIndexOf(array, value, fromIndex) { var index = array.length; + if (fromIndex && fromIndex === +fromIndex) { + index = (fromIndex < 0 ? Math.max(0, index + fromIndex) : Math.min(fromIndex, index - 1)) + 1; + } while (index--) { if (array[index] === value) { return index; @@ -1465,10 +1482,10 @@ } /** - * Uses a binary search to determine the smallest index at which the `value` - * should be inserted into the `collection` in order to maintain the sort order - * of the `collection`. If `callback` is passed, it will be executed for each - * value in the `collection` to compute their sort ranking. The `callback` is + * Uses a binary search to determine the smallest index at which the `value` + * should be inserted into the `array` in order to maintain the sort order + * of the `array`. If `callback` is passed, it will be executed for each + * value in the `array` to compute their sort ranking. The `callback` is * invoked with 1 argument; (value). * * @static @@ -1478,7 +1495,7 @@ * @param {Mixed} value The value to evaluate. * @param {Function} [callback] The function called per iteration. * @returns {Number} Returns the index at which the value should be inserted - * into the collection. + * into the array. * @example * * _.sortedIndex([10, 20, 30, 40, 50], 35); diff --git a/test/test.js b/test/test.js index 8b4f8d417..6442e4d96 100644 --- a/test/test.js +++ b/test/test.js @@ -254,6 +254,42 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.indexOf'); + + (function() { + var array = [1, 2, 3, 1, 2, 3]; + + test('should work with a positive `fromIndex`', function() { + equal(_.indexOf(array, 1, 2), 3); + }); + + test('should work with `fromIndex` >= `array.length`', function() { + equal(_.indexOf(array, 1, 6), -1); + equal(_.indexOf(array, undefined, 6), -1); + equal(_.indexOf(array, 1, 8), -1); + equal(_.indexOf(array, undefined, 8), -1); + }); + + test('should work with a negative `fromIndex`', function() { + equal(_.indexOf(array, 2, -3), 4); + }); + + test('should work with a negative `fromIndex` <= `-array.length`', function() { + equal(_.indexOf(array, 1, -6), 0); + equal(_.indexOf(array, 2, -8), 1); + }); + + test('should ignore non-number `fromIndex` values', function() { + equal(_.indexOf([1, 2, 3], 1, '1'), 0); + }); + + test('should work with `isSorted`', function() { + equal(_.indexOf([1, 2, 3], 1, true), 0); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.initial'); (function() { @@ -324,6 +360,39 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.lastIndexOf'); + + (function() { + var array = [1, 2, 3, 1, 2, 3]; + + test('should work with a positive `fromIndex`', function() { + equal(_.lastIndexOf(array, 1, 2), 0); + }); + + test('should work with `fromIndex` >= `array.length`', function() { + equal(_.lastIndexOf(array, undefined, 6), -1); + equal(_.lastIndexOf(array, 1, 6), 3); + equal(_.lastIndexOf(array, undefined, 8), -1); + equal(_.lastIndexOf(array, 1, 8), 3); + }); + + test('should work with a negative `fromIndex`', function() { + equal(_.lastIndexOf(array, 2, -3), 1); + }); + + test('should work with a negative `fromIndex` <= `-array.length`', function() { + equal(_.lastIndexOf(array, 1, -6), 0); + equal(_.lastIndexOf(array, 2, -8), -1); + }); + + test('should ignore non-number `fromIndex` values', function() { + equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2); + equal(_.lastIndexOf([1, 2, 3], 3, true), 2); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.partial'); (function() {