diff --git a/lodash.src.js b/lodash.src.js index 934f98cfb..a9d83f8c3 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5044,10 +5044,30 @@ /** * Uses a binary search to determine the lowest index at which `value` should - * be inserted into `array` in order to maintain its sort order. If an iteratee - * function is provided it's invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is invoked with one argument: - * (value). + * be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + * + * _.sortedIndex([4, 5], 4); + * // => 0 + */ + function sortedIndex(array, value) { + return binaryIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts an iteratee + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ @@ -5058,27 +5078,17 @@ * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * - * _.sortedIndex([30, 50], 40); - * // => 1 - * - * _.sortedIndex([4, 4, 5, 5], 5); - * // => 2 - * * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; * - * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); + * _.sortedIndexBy(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); * // => 1 * * // using the `_.property` callback shorthand - * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 1 + * _.sortedIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 0 */ - function sortedIndex(array, value, iteratee) { - var toIteratee = getIteratee(); - return (iteratee == null && toIteratee === baseIteratee) - ? binaryIndex(array, value) - : binaryIndexBy(array, value, toIteratee(iteratee)); + function sortedIndexBy(array, value, iteratee) { + return binaryIndexBy(array, value, getIteratee(iteratee)); } /** @@ -5091,18 +5101,36 @@ * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * _.sortedLastIndex([4, 5], 4); + * // => 1 + */ + function sortedLastIndex(array, value) { + return binaryIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts an iteratee + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * - * _.sortedLastIndex([4, 4, 5, 5], 5); - * // => 4 + * // using the `_.property` callback shorthand + * _.sortedLastIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 1 */ - function sortedLastIndex(array, value, iteratee) { - var toIteratee = getIteratee(); - return (iteratee == null && toIteratee === baseIteratee) - ? binaryIndex(array, value, true) - : binaryIndexBy(array, value, toIteratee(iteratee), true); + function sortedLastIndexBy(array, value, iteratee) { + return binaryIndexBy(array, value, getIteratee(iteratee), true); } /** @@ -11526,7 +11554,9 @@ lodash.snakeCase = snakeCase; lodash.some = some; lodash.sortedIndex = sortedIndex; + lodash.sortedIndexBy = sortedIndexBy; lodash.sortedLastIndex = sortedLastIndex; + lodash.sortedLastIndexBy = sortedLastIndexBy; lodash.startCase = startCase; lodash.startsWith = startsWith; lodash.sum = sum; diff --git a/test/test.js b/test/test.js index fdc6b4d06..962ff8de8 100644 --- a/test/test.js +++ b/test/test.js @@ -8739,12 +8739,12 @@ } }); - test('`_.sortedIndex` should use `_.iteratee` internally', 1, function() { + test('`_.sortedIndexBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedIndex(objects, { 'a': 40 }), 1); + strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { @@ -8752,12 +8752,12 @@ } }); - test('`_.sortedLastIndex` should use `_.iteratee` internally', 1, function() { + test('`_.sortedLastIndexBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedLastIndex(objects, { 'a': 40 }), 1); + strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { @@ -14323,13 +14323,12 @@ QUnit.module('sortedIndex methods'); _.each(['sortedIndex', 'sortedLastIndex'], function(methodName) { - var array = [30, 50], - func = _[methodName], - isSortedIndex = methodName == 'sortedIndex', - objects = [{ 'x': 30 }, { 'x': 50 }]; + var func = _[methodName], + isSortedIndex = methodName == 'sortedIndex'; test('`_.' + methodName + '` should return the insert index', 1, function() { - var values = [30, 40, 50], + var array = [30, 50], + values = [30, 40, 50], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; var actual = _.map(values, function(value) { @@ -14361,21 +14360,6 @@ deepEqual(actual, expected); }); - test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { - var args; - - func(array, 40, function() { - args || (args = slice.call(arguments)); - }); - - deepEqual(args, [40]); - }); - - test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { - var actual = func(objects, { 'x': 40 }, 'x'); - strictEqual(actual, 1); - }); - test('`_.' + methodName + '` should align with `_.sortBy`', 10, function() { var expected = [1, '2', {}, null, undefined, NaN, NaN]; @@ -14390,6 +14374,32 @@ strictEqual(func(expected, NaN), isSortedIndex ? 5 : 7); }); }); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('sortedIndexBy methods'); + + _.each(['sortedIndexBy', 'sortedLastIndexBy'], function(methodName) { + var func = _[methodName], + isSortedIndexBy = methodName == 'sortedIndexBy'; + + test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { + var args; + + func([30, 50], 40, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, [40]); + }); + + test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { + var objects = [{ 'x': 30 }, { 'x': 50 }], + actual = func(objects, { 'x': 40 }, 'x'); + + strictEqual(actual, 1); + }); test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', 12, function() { _.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) { @@ -14402,7 +14412,7 @@ var steps = 0, actual = func(array, value, function(value) { steps++; return value; }); - var expected = (isSortedIndex ? !_.isNaN(value) : _.isFinite(value)) + var expected = (isSortedIndexBy ? !_.isNaN(value) : _.isFinite(value)) ? 0 : Math.min(length, MAX_ARRAY_INDEX); @@ -17347,7 +17357,7 @@ var args = arguments, array = [1, 2, 3, 4, 5, 6]; - test('should work with `arguments` objects', 27, function() { + test('should work with `arguments` objects', 28, function() { function message(methodName) { return '`_.' + methodName + '` should work with `arguments` objects'; } @@ -17374,6 +17384,7 @@ deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf')); deepEqual(_.rest(args, 4), [null, [3], null, 5], message('rest')); deepEqual(_.sortedIndex(args, 6), 5, message('sortedIndex')); + deepEqual(_.sortedLastIndex(args, 6), 5, message('sortedLastIndex')); deepEqual(_.take(args, 2), [1, null], message('take')); deepEqual(_.takeRight(args, 1), [5], message('takeRight')); deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile')); @@ -17514,7 +17525,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 209, function() { + test('should accept falsey arguments', 211, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) {