mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 15:27:50 +00:00
Split _.uniq out into _.uniqBy.
This commit is contained in:
committed by
John-David Dalton
parent
abd67d0786
commit
8ac1a67b7d
@@ -5328,18 +5328,14 @@
|
||||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||||
* for equality comparisons, in which only the first occurence of each element
|
||||
* is kept. Providing `true` for `isSorted` performs a faster search algorithm
|
||||
* for sorted arrays. If an iteratee function is provided it's invoked for
|
||||
* each element in the array to generate the criterion by which uniqueness
|
||||
* is computed. The iteratee is invoked with three arguments: (value, index, array).
|
||||
* for sorted arrays.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias unique
|
||||
* @category Array
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {boolean} [isSorted] Specify the array is sorted.
|
||||
* @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration.
|
||||
* @returns {Array} Returns the new duplicate-value-free array.
|
||||
* @returns {Array} Returns the new duplicate free array.
|
||||
* @example
|
||||
*
|
||||
* _.uniq([2, 1, 2]);
|
||||
@@ -5348,18 +5344,42 @@
|
||||
* // using `isSorted`
|
||||
* _.uniq([1, 1, 2], true);
|
||||
* // => [1, 2]
|
||||
*/
|
||||
function uniq(array, isSorted) {
|
||||
var length = array ? array.length : 0;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
return (isSorted && typeof isSorted == 'boolean' && getIndexOf() == baseIndexOf)
|
||||
? sortedUniq(array)
|
||||
: baseUniq(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.uniq` except that it accepts an iteratee which is
|
||||
* invoked for each value in `array` to generate the criterion by which
|
||||
* uniqueness is computed. The iteratee is invoked with three arguments:
|
||||
* (value, index, array).
|
||||
*
|
||||
* // using an iteratee function
|
||||
* _.uniq([1, 2.5, 1.5, 2], function(n) {
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Array
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {boolean} [isSorted] Specify the array is sorted.
|
||||
* @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration.
|
||||
* @returns {Array} Returns the new duplicate free array.
|
||||
* @example
|
||||
*
|
||||
* _.uniqBy([1, 2.5, 1.5, 2], function(n) {
|
||||
* return Math.floor(n);
|
||||
* });
|
||||
* // => [1, 2.5]
|
||||
*
|
||||
* // using the `_.property` callback shorthand
|
||||
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
||||
* _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
||||
* // => [{ 'x': 1 }, { 'x': 2 }]
|
||||
*/
|
||||
function uniq(array, isSorted, iteratee) {
|
||||
function uniqBy(array, isSorted, iteratee) {
|
||||
var length = array ? array.length : 0;
|
||||
if (!length) {
|
||||
return [];
|
||||
@@ -11444,6 +11464,7 @@
|
||||
lodash.transform = transform;
|
||||
lodash.union = union;
|
||||
lodash.uniq = uniq;
|
||||
lodash.uniqBy = uniqBy;
|
||||
lodash.unzip = unzip;
|
||||
lodash.unzipWith = unzipWith;
|
||||
lodash.values = values;
|
||||
|
||||
151
test/test.js
151
test/test.js
@@ -5963,8 +5963,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
test('`_.uniq` should work with a custom `_.indexOf` method', 6, function() {
|
||||
_.each([false, true, _.identity], function(param) {
|
||||
test('`_.uniq` should work with a custom `_.indexOf` method', 4, function() {
|
||||
_.each([false, true], function(param) {
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
deepEqual(_.uniq(array, param), array.slice(0, 3));
|
||||
@@ -5976,6 +5976,20 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('`_.uniqBy` should work with a custom `_.indexOf` method', 6, function() {
|
||||
_.each([[false, _.identity], [true, _.identity], [_.identity]], function(params) {
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
deepEqual(_.uniqBy.apply(_, [array].concat(params)), array.slice(0, 3));
|
||||
deepEqual(_.uniqBy.apply(_, [largeArray].concat(params)), [largeArray[0]]);
|
||||
_.indexOf = indexOf;
|
||||
}
|
||||
else {
|
||||
skipTest(2);
|
||||
}
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -8790,10 +8804,10 @@
|
||||
}
|
||||
});
|
||||
|
||||
test('`_.uniq` should use `_.iteratee` internally', 1, function() {
|
||||
test('`_.uniqBy` should use `_.iteratee` internally', 1, function() {
|
||||
if (!isModularize) {
|
||||
_.iteratee = getPropB;
|
||||
deepEqual(_.uniq(objects), [objects[0], objects[2]]);
|
||||
deepEqual(_.uniqBy(objects), [objects[0], objects[2]]);
|
||||
_.iteratee = iteratee;
|
||||
}
|
||||
else {
|
||||
@@ -13831,7 +13845,7 @@
|
||||
return _.shuffle([1, 2]);
|
||||
});
|
||||
|
||||
deepEqual(_.sortBy(_.uniq(actual, String), '0'), [[1, 2], [2, 1]]);
|
||||
deepEqual(_.sortBy(_.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]);
|
||||
});
|
||||
|
||||
test('should treat number values for `collection` as empty', 1, function() {
|
||||
@@ -16077,42 +16091,17 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.uniq');
|
||||
QUnit.module('lodash.uniqBy');
|
||||
|
||||
(function() {
|
||||
var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }];
|
||||
|
||||
test('should return unique values of an unsorted array', 1, function() {
|
||||
var array = [2, 3, 1, 2, 3, 1];
|
||||
deepEqual(_.uniq(array), [2, 3, 1]);
|
||||
});
|
||||
|
||||
test('should return unique values of a sorted array', 1, function() {
|
||||
var array = [1, 1, 2, 2, 3];
|
||||
deepEqual(_.uniq(array), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('should treat object instances as unique', 1, function() {
|
||||
deepEqual(_.uniq(objects), objects);
|
||||
});
|
||||
|
||||
test('should not treat `NaN` as unique', 1, function() {
|
||||
deepEqual(_.uniq([1, NaN, 3, NaN]), [1, NaN, 3]);
|
||||
});
|
||||
|
||||
test('should work with `isSorted`', 3, function() {
|
||||
var expected = [1, 2, 3];
|
||||
deepEqual(_.uniq([1, 2, 3], true), expected);
|
||||
deepEqual(_.uniq([1, 1, 2, 2, 3], true), expected);
|
||||
deepEqual(_.uniq([1, 2, 3, 3, 3, 3, 3], true), expected);
|
||||
});
|
||||
|
||||
test('should work with an `iteratee` argument', 2, function() {
|
||||
_.each([objects, _.sortBy(objects, 'a')], function(array, index) {
|
||||
var isSorted = !!index,
|
||||
expected = isSorted ? [objects[2], objects[0], objects[1]] : objects.slice(0, 3);
|
||||
|
||||
var actual = _.uniq(array, isSorted, function(object) {
|
||||
var actual = _.uniqBy(array, isSorted, function(object) {
|
||||
return object.a;
|
||||
});
|
||||
|
||||
@@ -16123,7 +16112,7 @@
|
||||
test('should provide the correct `iteratee` arguments', 1, function() {
|
||||
var args;
|
||||
|
||||
_.uniq(objects, function() {
|
||||
_.uniqBy(objects, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
@@ -16131,7 +16120,7 @@
|
||||
});
|
||||
|
||||
test('should work with `iteratee` without specifying `isSorted`', 1, function() {
|
||||
var actual = _.uniq(objects, function(object) {
|
||||
var actual = _.uniqBy(objects, function(object) {
|
||||
return object.a;
|
||||
});
|
||||
|
||||
@@ -16139,24 +16128,71 @@
|
||||
});
|
||||
|
||||
test('should work with a "_.property" style `iteratee`', 2, function() {
|
||||
var actual = _.uniq(objects, 'a');
|
||||
var actual = _.uniqBy(objects, 'a');
|
||||
|
||||
deepEqual(actual, objects.slice(0, 3));
|
||||
|
||||
var arrays = [[2], [3], [1], [2], [3], [1]];
|
||||
actual = _.uniq(arrays, 0);
|
||||
actual = _.uniqBy(arrays, 0);
|
||||
|
||||
deepEqual(actual, arrays.slice(0, 3));
|
||||
});
|
||||
|
||||
test('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', 1, function() {
|
||||
_.each({
|
||||
'an array': [0, 'a'],
|
||||
'an object': { '0': 'a' },
|
||||
'a number': 0,
|
||||
'a string': '0'
|
||||
},
|
||||
function(iteratee, key) {
|
||||
test('should work with ' + key + ' for `iteratee`', 1, function() {
|
||||
var actual = _.uniqBy([['a'], ['b'], ['a']], iteratee);
|
||||
deepEqual(actual, [['a'], ['b']]);
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('uniq methods');
|
||||
|
||||
_.each(['uniq', 'uniqBy'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }];
|
||||
|
||||
test('`_.' + methodName + '` should return unique values of an unsorted array', 1, function() {
|
||||
var array = [2, 3, 1, 2, 3, 1];
|
||||
deepEqual(func(array), [2, 3, 1]);
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '` should return unique values of a sorted array', 1, function() {
|
||||
var array = [1, 1, 2, 2, 3];
|
||||
deepEqual(func(array), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '` should treat object instances as unique', 1, function() {
|
||||
deepEqual(func(objects), objects);
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '` should not treat `NaN` as unique', 1, function() {
|
||||
deepEqual(func([1, NaN, 3, NaN]), [1, NaN, 3]);
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '` should work with `isSorted`', 3, function() {
|
||||
var expected = [1, 2, 3];
|
||||
deepEqual(func([1, 2, 3], true), expected);
|
||||
deepEqual(func([1, 1, 2, 2, 3], true), expected);
|
||||
deepEqual(func([1, 2, 3, 3, 3, 3, 3], true), expected);
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '` should perform an unsorted uniq when used as an iteratee for methods like `_.map`', 1, function() {
|
||||
var array = [[2, 1, 2], [1, 2, 1]],
|
||||
actual = _.map(array, _.uniq);
|
||||
actual = _.map(array, func);
|
||||
|
||||
deepEqual(actual, [[2, 1], [1, 2]]);
|
||||
});
|
||||
|
||||
test('should work with large arrays', 1, function() {
|
||||
test('`_.' + methodName + '` should work with large arrays', 1, function() {
|
||||
var largeArray = [],
|
||||
expected = [0, 'a', {}],
|
||||
count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
|
||||
@@ -16165,10 +16201,10 @@
|
||||
push.apply(largeArray, expected);
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(largeArray), expected);
|
||||
deepEqual(func(largeArray), expected);
|
||||
});
|
||||
|
||||
test('should work with large arrays of boolean, `NaN`, and nullish values', 1, function() {
|
||||
test('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', 1, function() {
|
||||
var largeArray = [],
|
||||
expected = [true, false, NaN, null, undefined],
|
||||
count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
|
||||
@@ -16177,24 +16213,24 @@
|
||||
push.apply(largeArray, expected);
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(largeArray), expected);
|
||||
deepEqual(func(largeArray), expected);
|
||||
});
|
||||
|
||||
test('should work with large arrays of symbols', 1, function() {
|
||||
test('`_.' + methodName + '` should work with large arrays of symbols', 1, function() {
|
||||
if (Symbol) {
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function() {
|
||||
return Symbol();
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(largeArray), largeArray);
|
||||
deepEqual(func(largeArray), largeArray);
|
||||
}
|
||||
else {
|
||||
skipTest();
|
||||
}
|
||||
});
|
||||
|
||||
test('should work with large arrays of well-known symbols', 1, function() {
|
||||
// See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-symbols.
|
||||
test('`_.' + methodName + '` should work with large arrays of well-known symbols', 1, function() {
|
||||
// See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols.
|
||||
if (Symbol) {
|
||||
var expected = [
|
||||
Symbol.hasInstance, Symbol.isConcatSpreadable, Symbol.iterator,
|
||||
@@ -16213,14 +16249,14 @@
|
||||
push.apply(largeArray, expected);
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(largeArray), expected);
|
||||
deepEqual(func(largeArray), expected);
|
||||
}
|
||||
else {
|
||||
skipTest();
|
||||
}
|
||||
});
|
||||
|
||||
test('should distinguish between numbers and numeric strings', 1, function() {
|
||||
test('`_.' + methodName + '` should distinguish between numbers and numeric strings', 1, function() {
|
||||
var array = [],
|
||||
expected = ['2', 2, Object('2'), Object(2)],
|
||||
count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
|
||||
@@ -16229,22 +16265,9 @@
|
||||
push.apply(array, expected);
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(array), expected);
|
||||
deepEqual(func(array), expected);
|
||||
});
|
||||
|
||||
_.each({
|
||||
'an array': [0, 'a'],
|
||||
'an object': { '0': 'a' },
|
||||
'a number': 0,
|
||||
'a string': '0'
|
||||
},
|
||||
function(callback, key) {
|
||||
test('should work with ' + key + ' for `iteratee`', 1, function() {
|
||||
var actual = _.uniq([['a'], ['b'], ['a']], callback);
|
||||
deepEqual(actual, [['a'], ['b']]);
|
||||
});
|
||||
});
|
||||
}());
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
@@ -17515,7 +17538,7 @@
|
||||
|
||||
var acceptFalsey = _.difference(allMethods, rejectFalsey);
|
||||
|
||||
test('should accept falsey arguments', 207, function() {
|
||||
test('should accept falsey arguments', 208, function() {
|
||||
var emptyArrays = _.map(falsey, _.constant([]));
|
||||
|
||||
_.each(acceptFalsey, function(methodName) {
|
||||
|
||||
Reference in New Issue
Block a user