Skip to content

Commit a13ab06

Browse files
Issue #44 Export intersection function from lodash
Added lodash intersection and intersectionWith to CollectionUtils
2 parents 8ca5c8d + cde0652 commit a13ab06

2 files changed

Lines changed: 139 additions & 28 deletions

File tree

src/utilities/collection-utils.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ describe("CollectionUtils", () => {
398398
const result = CollectionUtils.equalsBy(selector, arr1, arr2);
399399

400400
// Assert
401-
expect(result).toBe(false);
401+
expect(result).toBeFalse();
402402
});
403403

404404
it("when one of the collections is null, then returns false", () => {
@@ -409,7 +409,7 @@ describe("CollectionUtils", () => {
409409
const result = CollectionUtils.equalsBy(selector, arr1, undefined);
410410

411411
// Assert
412-
expect(result).toBe(false);
412+
expect(result).toBeFalse();
413413
});
414414

415415
it("when both collections are null, then returns true", () => {
@@ -421,7 +421,7 @@ describe("CollectionUtils", () => {
421421
);
422422

423423
// Assert
424-
expect(result).toBe(true);
424+
expect(result).toBeTrue();
425425
});
426426

427427
it("when collections are equal size but contain different elements, then returns false", () => {
@@ -433,7 +433,7 @@ describe("CollectionUtils", () => {
433433
const result = CollectionUtils.equalsBy(selector, arr1, arr2);
434434

435435
// Assert
436-
expect(result).toBe(false);
436+
expect(result).toBeFalse();
437437
});
438438

439439
it("when collections are identical, then returns true", () => {
@@ -445,7 +445,7 @@ describe("CollectionUtils", () => {
445445
const result = CollectionUtils.equalsBy(selector, arr1, arr2);
446446

447447
// Assert
448-
expect(result).toBe(true);
448+
expect(result).toBeTrue();
449449
});
450450
});
451451

src/utilities/collection-utils.ts

Lines changed: 134 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { List } from "immutable";
1+
import * as Immutable from "immutable";
22
import _ from "lodash";
33

4+
45
// -----------------------------------------------------------------------------------------
56
// #region Private Methods
67
// -----------------------------------------------------------------------------------------
@@ -18,8 +19,8 @@ import _ from "lodash";
1819
*/
1920
const _equalsBy = function<T, V>(
2021
selector: (element: T) => V,
21-
array1: Array<T> | List<any> | undefined,
22-
array2: Array<T> | List<any> | undefined
22+
array1: Array<T> | Immutable.List<any> | undefined,
23+
array2: Array<T> | Immutable.List<any> | undefined
2324
) {
2425
if (array1 == null) {
2526
return array2 == null;
@@ -44,22 +45,46 @@ const _equalsBy = function<T, V>(
4445
return !hasDifferingValues;
4546
};
4647

48+
49+
/**
50+
* Creates an array of unique array values not included in the other provided arrays using SameValueZero for
51+
* equality comparisons.
52+
*
53+
* @param array The array to inspect.
54+
* @param values The arrays of values to exclude.
55+
* @return Returns the new array of filtered values.
56+
*/
57+
const _difference = <T>(
58+
array: Array<T> | null | undefined,
59+
...values: Array<Array<T>>
60+
): T[] => _.difference(array, ...values);
61+
62+
63+
/**
64+
* Recursively flattens a nested array.
65+
*
66+
* @param array The array to recursively flatten.
67+
* @return Returns the new flattened array.
68+
*/
69+
const _flattenDeep = <T>(array: Array<T> | null | undefined): T[] => _.flattenDeep(array);
70+
71+
4772
/**
4873
* Checks for values in a collection/object. Returns false if the collection is undefined, null,
4974
* or the respective object type's "empty" state, ie length 0, size 0, or has no keys.
5075
*
5176
* Uses ... syntax to allow a single collection or multiple collections to be passed in, ie
5277
* CollectionUtils.hasValues([]) or CollectionUtils.hasValues([], [], [])
5378
*
54-
* @param {(...Array<(any[] | List<any>)} collections
79+
* @param {(...Array<(any[] | Immutable.List<any>)} collections
5580
* @returns {boolean} False if `collections` is null/undefined, or every element is also null/undefined,
5681
* or has no sub-elements. True if any element has sub-elements.
5782
*/
5883
const _hasValues = (
59-
...collections: Array<any[] | List<any> | undefined>
84+
...collections: Array<any[] | Immutable.List<any> | undefined>
6085
): boolean => {
6186
let hasValues = false;
62-
collections.forEach((collection: any[] | List<any> | undefined) => {
87+
collections.forEach((collection: any[] | Immutable.List<any> | undefined) => {
6388
if (!_isEmpty(collection)) {
6489
hasValues = true;
6590
}
@@ -74,21 +99,21 @@ const _hasValues = (
7499
* Uses ... syntax to allow a single collection or multiple collections to be passed in, ie
75100
* CollectionUtils.isEmpty([]) or CollectionUtils.isEmpty([], [], [])
76101
*
77-
* @param {(...Array<(any[] | List<any>)} collections
102+
* @param {(...Array<(any[] | Immutable.List<any>)} collections
78103
* @returns {boolean} True if `collections` is null/undefined, or every element is also null/undefined,
79104
* or has no sub-elements. False if any element has sub-elements.
80105
*/
81106
const _isEmpty = (
82-
...collections: Array<any[] | List<any> | undefined>
107+
...collections: Array<any[] | Immutable.List<any> | undefined>
83108
): boolean => {
84109
let isEmpty = true;
85110

86-
collections.forEach((collection: any[] | List<any> | undefined) => {
111+
collections.forEach((collection: any[] | Immutable.List<any> | undefined) => {
87112
if (collection == null) {
88113
return;
89114
}
90-
if (collection instanceof List) {
91-
const collectionList = collection as List<any>;
115+
if (collection instanceof Immutable.List) {
116+
const collectionList = collection as Immutable.List<any>;
92117
if (collectionList.size !== 0) {
93118
isEmpty = false;
94119
}
@@ -110,34 +135,82 @@ const _isEmpty = (
110135
* Uses ... syntax to allow a single collection or multiple collections to be passed in, ie
111136
* CollectionUtils.isNotEmpty([]) or CollectionUtils.isNotEmpty([], [], [])
112137
*
113-
* @param {(...Array<(any[] | List<any>)} collections
138+
* @param {(...Array<(any[] | Immutable.List<any>)} collections
114139
* @returns {boolean} False if `collections` is null/undefined, or every element is also null/undefined,
115140
* or has no sub-elements. True if any element has sub-elements.
116141
*/
117142
const _isNotEmpty = (
118-
...collections: Array<any[] | List<any> | undefined>
143+
...collections: Array<any[] | Immutable.List<any> | undefined>
119144
): boolean => {
120145
return !_isEmpty(...collections);
121146
};
122147

123148
/**
124149
* Utility function to get the length of a collection
125-
* when the collection might be either a List or an Array
150+
* when the collection might be either a Immutable.List or an Array
126151
* @param arr the collection
127152
* @returns number the length of the collection
128153
*/
129-
const _length = (arr: Array<any> | List<any>): number => {
154+
const _length = (arr: Array<any> | Immutable.List<any>): number => {
130155
if (arr == null) {
131156
return -1;
132157
}
133158

134-
if (arr instanceof List) {
135-
return (arr as List<any>).size;
159+
if (arr instanceof Immutable.List) {
160+
return (arr as Immutable.List<any>).size;
136161
}
137162

138163
return (arr as Array<any>).length;
139164
};
140165

166+
167+
/**
168+
* Gets the first element of array.
169+
*
170+
* @alias _.first
171+
*
172+
* @param array The array to query.
173+
* @return Returns the first element of array.
174+
*/
175+
const _head = <T>(array: Array<T> | null | undefined): T | undefined => _.head(array);
176+
177+
178+
/**
179+
* Creates an array of unique values that are included in all of the provided arrays using SameValueZero for
180+
* equality comparisons.
181+
*
182+
* @param arrays The arrays to inspect.
183+
* @return Returns the new array of shared values.
184+
*/
185+
const _intersection = <T>(...arrays: Array<Array<T>>) => _.intersection(...arrays)
186+
187+
188+
189+
/**
190+
* Creates an array of unique `array` values not included in the other
191+
* provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
192+
* for equality comparisons.
193+
*
194+
* @category Array
195+
* @param array
196+
* @param [values] The arrays to inspect.
197+
* @param [comparator] The comparator invoked per element.
198+
* @returns Returns the new array of filtered values.
199+
* @example
200+
*
201+
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
202+
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
203+
204+
* _.intersectionWith(objects, others, _.isEqual);
205+
* => [{ 'x': 1, 'y': 2 }]
206+
*/
207+
const _intersectionWith = <T1, T2>(
208+
array: Array<T1>,
209+
values: Array<T2>,
210+
comparator: (a: T1, b: T2) => boolean
211+
): T1[] => _.intersectionWith(array, values, comparator);
212+
213+
141214
/**
142215
* Removes a supplied element by index
143216
* @param source original array
@@ -153,6 +226,7 @@ const _removeElementAt = <T>(source: Array<T>, index: number): Array<T> => {
153226
return newArr;
154227
};
155228

229+
156230
/**
157231
* Returns a NEW array with the element at the specified index
158232
* replaced with the specified value if the index provided is
@@ -182,6 +256,29 @@ const _replaceElementAt = <T>(
182256
return [...source.slice(0, index), value, ...source.slice(index + 1)];
183257
};
184258

259+
/**
260+
* Gets a random element from collection.
261+
*
262+
* @param collection The collection to sample.
263+
* @return Returns the random element.
264+
*/
265+
const _sample = <T>(
266+
collection: Array<T> | null | undefined
267+
): T | undefined => _.sample(collection);
268+
269+
270+
/**
271+
* Gets n random elements at unique keys from collection up to the size of collection.
272+
*
273+
* @param collection The collection to sample.
274+
* @param n The number of elements to sample.
275+
* @return Returns the random elements.
276+
*/
277+
const _sampleSize = <T>(
278+
collection: Array<T> | null | undefined,
279+
n?: number
280+
): T[] => _.sampleSize(collection, n);
281+
185282
/**
186283
* Sort an array of items alphabetically by one property of the item.
187284
* @param array the source array of items
@@ -220,6 +317,18 @@ const _sortByString = <T extends any>(
220317

221318
return 1;
222319
});
320+
321+
/**
322+
* Creates a slice of array with n elements taken from the beginning.
323+
*
324+
* @param array The array to query.
325+
* @param n The number of elements to take.
326+
* @return Returns the slice of array.
327+
*/
328+
const _take = <T>(
329+
array: Array<T> | null | undefined,
330+
n?: number
331+
): T[] => _.take(array, n);
223332

224333
// #endregion Private Methods
225334

@@ -228,20 +337,22 @@ const _sortByString = <T extends any>(
228337
// -----------------------------------------------------------------------------------------
229338

230339
export const CollectionUtils = {
231-
difference: _.difference,
340+
difference: _difference,
232341
equalsBy: _equalsBy,
233-
first: _.head,
234-
flattenDeep: _.flattenDeep,
342+
first: _head,
343+
flattenDeep: _flattenDeep,
235344
hasValues: _hasValues,
236345
isEmpty: _isEmpty,
237346
isNotEmpty: _isNotEmpty,
347+
intersection: _intersection,
348+
intersectionWith: _intersectionWith,
238349
length: _length,
239350
removeElementAt: _removeElementAt,
240351
replaceElementAt: _replaceElementAt,
241-
sample: _.sample,
242-
sampleSize: _.sampleSize,
352+
sample: _sample,
353+
sampleSize: _sampleSize,
243354
sortByString: _sortByString,
244-
take: _.take,
355+
take: _take,
245356
};
246357

247358
// #endregion Exports

0 commit comments

Comments
 (0)