diff --git a/lodash.js b/lodash.js index d61413c91..5afd69f01 100644 --- a/lodash.js +++ b/lodash.js @@ -2380,17 +2380,35 @@ return high; } + /** + * The implementation of `_.uniq` optimized for sorted arrays + * + * @private + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate-value-free array. + */ + function sortedUniq(array) { + var result = [], + index = -1, + length = array ? array.length : 0; + while (++index < length) { + if (index + 1 > length || array[index] !== array[index + 1]) { + result.push(array[index]); + } + } + return result; + }; + /** * The base implementation of `_.uniq` without support for callback shorthands * and `this` binding. * * @private * @param {Array} array The array to inspect. - * @param {boolean} [isSorted=false] Specify the array is sorted. * @param {Function} [iterator] The function called per iteration. * @returns {Array} Returns the new duplicate-value-free array. */ - function baseUniq(array, isSorted, iterator) { + function baseUniq(array, iterator) { var length = array ? array.length : 0; if (!length) { return []; @@ -2402,12 +2420,11 @@ isCommon = prereq && !isLarge, result = []; - isSorted = prereq && isSorted; if (isLarge) { var seen = createCache(); indexOf = cacheIndexOf; } else { - seen = (iterator && !isSorted) ? [] : result; + seen = iterator ? [] : result; } outer: while (++index < length) { @@ -2426,12 +2443,6 @@ } result.push(value); } - else if (isSorted) { - if (!index || seen !== computed) { - seen = computed; - result.push(value); - } - } else if (indexOf(seen, computed) < 0) { if (iterator || isLarge) { seen.push(computed); @@ -4095,26 +4106,23 @@ * // => [{ 'x': 1 }, { 'x': 2 }] */ function uniq(array, isSorted, iterator, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } // juggle arguments var type = typeof isSorted; if (type != 'boolean' && isSorted != null) { thisArg = iterator; iterator = isSorted; - isSorted = false; // enables use as a callback for functions like `_.map` if ((type == 'number' || type == 'string') && thisArg && thisArg[iterator] === array) { iterator = null; } + } else if (isSorted && getIndexOf() == baseIndexOf) { + return sortedUniq(array); } if (iterator != null) { iterator = getCallback(iterator, thisArg, 3); } - return baseUniq(array, isSorted, iterator); + return baseUniq(array, iterator); } /** diff --git a/test/test.js b/test/test.js index 7d0cdafc2..ba52874f5 100644 --- a/test/test.js +++ b/test/test.js @@ -10683,9 +10683,11 @@ deepEqual(_.uniq(objects), objects); }); - test('should work with `isSorted`', 1, function() { - var array = [1, 1, 2, 2, 3]; + test('should work with `isSorted`', 4, function() { deepEqual(_.uniq([1, 1, 2, 2, 3], true), [1, 2, 3]); + deepEqual(_.uniq(_.range(100), true), _.range(100)); + deepEqual(_.uniq(_.times(100, _.constant(undefined))), [undefined]); + deepEqual(_.uniq([1, 2, 3, 3, 3, 3, 3]), [1, 2, 3]); }); test('should work with a callback', 1, function() {