Skip to content

Commit bf6a040

Browse files
authored
feat: add union, intersection, and difference list utilities (#9)
1 parent 0795626 commit bf6a040

3 files changed

Lines changed: 71 additions & 1 deletion

File tree

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bytebury/toolkit",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"exports": "./mod.ts",
55
"tasks": {
66
"dev": "deno test --watch"

src/core.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,10 @@ export function inRange(value: number, min: number, max: number): boolean {
382382
* Splits an array into chunks of a fixed size.
383383
*
384384
* @example
385+
* ```ts
385386
* chunk([1,2,3,4,5,6,7], 3); // [[1,2,3],[4,5,6],[7]]
386387
* chunk(['a','b','c','d'], 2); // [['a','b'], ['c','d']]
388+
* ```
387389
*/
388390
export function chunk<T>(arr: T[], size: number): T[][] {
389391
if (size <= 0) throw new Error("chunk size must be > 0");
@@ -394,3 +396,53 @@ export function chunk<T>(arr: T[], size: number): T[][] {
394396
}
395397
return result;
396398
}
399+
400+
/**
401+
* Returns the union of multiple arrays.
402+
*
403+
* @example
404+
* ```ts
405+
* union([1,2,3], [2,3,4]); // [1,2,3,4]
406+
* union(['a','b','c'], ['b','c','d']); // ['a','b','c','d']
407+
* ```
408+
*/
409+
export function union<T>(...lists: T[][]): T[] {
410+
return [...new Set(lists.flat())];
411+
}
412+
413+
/**
414+
* Returns the difference of multiple arrays.
415+
*
416+
* @example
417+
* ```ts
418+
* difference([1,2,3], [2,3,4]); // [1]
419+
* difference(['a','b','c'], ['b','c','d']); // ['a']
420+
* ```
421+
*/
422+
export function difference<T>(...lists: T[][]): T[] {
423+
const set = new Set(lists[0]);
424+
for (const list of lists.slice(1)) {
425+
for (const item of list) {
426+
set.delete(item);
427+
}
428+
}
429+
return Array.from(set);
430+
}
431+
432+
/**
433+
* Returns the intersection of multiple arrays.
434+
*
435+
* @example
436+
* ```ts
437+
* intersection([1,2,3], [2,3,4]); // [2,3]
438+
* intersection(['a','b','c'], ['b','c','d']); // ['b','c']
439+
* ```
440+
*/
441+
export function intersection<T>(...lists: T[][]): T[] {
442+
if (lists.length === 0) return [];
443+
444+
return lists.reduce((acc, current) => {
445+
const currentSet = new Set(current);
446+
return acc.filter((item) => currentSet.has(item));
447+
});
448+
}

src/core_test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import {
99
import {
1010
chunk,
1111
clone,
12+
difference,
1213
distinct,
1314
falsy,
1415
first,
1516
inRange,
17+
intersection,
1618
isEmpty,
1719
isEqual,
1820
isEqualIgnoreCase,
@@ -28,6 +30,7 @@ import {
2830
sample,
2931
stringify,
3032
truthy,
33+
union,
3134
unique,
3235
} from "../src/core.ts";
3336
import type { NonEmptyList } from "./utility_types.ts";
@@ -308,3 +311,18 @@ Deno.test("chunk", () => {
308311
assertStrictEquals(chunk([1, 2, 3], 2)[0].length, 2);
309312
assertStrictEquals(chunk([1, 2, 3], 2)[1].length, 1);
310313
});
314+
315+
Deno.test("difference", () => {
316+
assertStrictEquals(difference([1, 2, 3], [2, 3, 4]).length, 1);
317+
assertStrictEquals(difference(["a", "b", "c"], ["b", "c", "d"]).length, 1);
318+
});
319+
320+
Deno.test("intersection", () => {
321+
assertStrictEquals(intersection([1, 2, 3], [2, 3, 4]).length, 2);
322+
assertStrictEquals(intersection(["a", "b", "c"], ["b", "c", "d"]).length, 2);
323+
});
324+
325+
Deno.test("union", () => {
326+
assertStrictEquals(union([1, 2, 3], [2, 3, 4]).length, 4);
327+
assertStrictEquals(union(["a", "b", "c"], ["b", "c", "d"]).length, 4);
328+
});

0 commit comments

Comments
 (0)