├── docs ├── .nojekyll ├── size.md ├── has.md ├── tosimpleset.md ├── isempty.md ├── clear.md ├── toarray.md ├── union.md ├── add.md ├── complement.md ├── difference.md ├── foreach.md ├── issubsetof.md ├── isdisjointwith.md ├── issupersetof.md ├── _sidebar.md ├── equals.md ├── filter.md ├── intersection.md ├── map.md ├── delete.md ├── reduce.md ├── index.html ├── createSubset.md └── README.md ├── .gitignore ├── .travis.yml ├── tslint.json ├── .prettierrc ├── jestconfig.json ├── tsconfig.json ├── src ├── __tests__ │ ├── ToArray.test.ts │ ├── IsEmpty.test.ts │ ├── Constructor.test.ts │ ├── Every.test.ts │ ├── Complement.test.ts │ ├── CreateSubset.test.ts │ ├── Add.test.ts │ ├── Iterator.test.ts │ ├── IsDisjointWith.test.ts │ ├── Some.test.ts │ ├── ForEach.test.ts │ ├── Filter.test.ts │ ├── Intersection.test.ts │ ├── Equals.test.ts │ ├── Map.test.ts │ ├── Difference.test.ts │ ├── Reduce.test.ts │ ├── IsSubsetOf.test.ts │ ├── IsSuperSetOf.test.ts │ └── Union.test.ts └── AdvancedSet.ts ├── README.md ├── LICENSE └── package.json /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'stable' 4 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /jestconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "transform": { 3 | "^.+\\.(t|j)sx?$": "ts-jest" 4 | }, 5 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "downlevelIteration": true, 7 | "outDir": "./lib", 8 | "strict": true 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules", "**/__tests__/*"] 12 | } 13 | -------------------------------------------------------------------------------- /src/__tests__/ToArray.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Empty set to array', () => { 4 | expect(new AdvancedSet().toArray()).toMatchObject([]); 5 | }); 6 | 7 | test('Non empty set to array', () => { 8 | expect(new AdvancedSet(1, 7, 18).toArray().sort()).toMatchObject([1, 7, 18].sort()); 9 | }); 10 | -------------------------------------------------------------------------------- /src/__tests__/IsEmpty.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An empty set should return true with isEmpty', () => { 4 | expect(new AdvancedSet().isEmpty()).toBe(true); 5 | }); 6 | 7 | test('A non empty set should return false with isEmpty', () => { 8 | expect(new AdvancedSet(1, 3, 10).isEmpty()).toBe(false); 9 | }); 10 | -------------------------------------------------------------------------------- /docs/size.md: -------------------------------------------------------------------------------- 1 | # .size 2 | 3 | ### Overview 4 | 5 | The number of elements in the set. 6 | 7 | `get size(): number` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.size; // 5 18 | 19 | const setB = new AdvancedSet(); 20 | setB.size; // 0 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /docs/has.md: -------------------------------------------------------------------------------- 1 | # .has() 2 | 3 | ### Overview 4 | 5 | Returns if the set has the given element. 6 | 7 | `has(val: T): boolean` 8 | 9 | ### Parameters 10 | 11 | `val` - The element to look for. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.has(1); // true 18 | setB.has(0); // false 19 | ``` 20 | 21 | ### Details 22 | 23 | Introduced in: 0.0.1 24 | 25 | Last updated in: 0.0.1 26 | -------------------------------------------------------------------------------- /docs/tosimpleset.md: -------------------------------------------------------------------------------- 1 | # .toSimpleSet() 2 | 3 | ### Overview 4 | 5 | Returns the current `AdvancedSet` as a simple JavaScript `Set`. 6 | 7 | `toSimpleSet(): Set` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | set.toSimpleSet(); // Set([1, 2, 3, 4, 5]) 18 | ``` 19 | 20 | ### Details 21 | 22 | Introduced in: 0.0.1 23 | 24 | Last updated in: 0.0.1 25 | -------------------------------------------------------------------------------- /docs/isempty.md: -------------------------------------------------------------------------------- 1 | # .isEmpty() 2 | 3 | ### Overview 4 | 5 | Returns whether or not the set contains no elements. 6 | 7 | `isEmpty(): boolean` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(); 17 | setA.isEmtpy(); // true 18 | 19 | const setB = new AdvancedSet(1, 2, 3); 20 | setB.isEmtpy(); // false 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /docs/clear.md: -------------------------------------------------------------------------------- 1 | # .clear() 2 | 3 | ### Overview 4 | 5 | Removes all elements within the set. 6 | 7 | `clear(): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.clear(); // AdvancedSet() 18 | 19 | // Original object is changed, as well as the return value 20 | console.log(setA); // AdvancedSet() 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /docs/toarray.md: -------------------------------------------------------------------------------- 1 | # .toArray() 2 | 3 | ### Overview 4 | 5 | Returns all of the elements in the set in an array. Since sets do not have an order to their elements, the order of elements in the array is not guaranteed. 6 | 7 | `toArray(): T[]` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.toArray().sort(); // [1, 2, 3, 4, 5] 18 | ``` 19 | 20 | ### Details 21 | 22 | Introduced in: 0.0.1 23 | 24 | Last updated in: 0.0.1 25 | -------------------------------------------------------------------------------- /docs/union.md: -------------------------------------------------------------------------------- 1 | # .union() 2 | 3 | ### Overview 4 | 5 | Returns a set containing all elements in _either_ set. 6 | 7 | `union(setB: AdvancedSet): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set union with the caller set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | const setB = new AdvancedSet(1, 2, 6); 18 | 19 | setA.union(setB); // AdvancedSet(1, 2, 3, 4, 5, 6) 20 | ``` 21 | 22 | ### Details 23 | 24 | Introduced in: 0.0.1 25 | 26 | Last updated in: 0.0.1 27 | -------------------------------------------------------------------------------- /docs/add.md: -------------------------------------------------------------------------------- 1 | # .add() 2 | 3 | ### Overview 4 | 5 | Adds an element to the existing set. Returns the current set (with the new element). 6 | 7 | `add(val: T): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `val` - The element to add to the set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.add(0); // AdvancedSet(1, 2, 3, 4, 5, 0) 18 | 19 | // Original object is changed, as well as the return value 20 | console.log(setA); // AdvancedSet(1, 2, 3, 4, 5, 0) 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /docs/complement.md: -------------------------------------------------------------------------------- 1 | # .complement() 2 | 3 | ### Overview 4 | 5 | Finds all of the elements that are _not_ in the given subset. Can only be used if the set has a defined parent, which is done with [createSubset](createSubset.md). 6 | 7 | `complement(): AdvancedSet ` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | ### Usage 14 | 15 | ```js 16 | const universalSet = new AdvancedSet(1, 2, 3, 4, 5); 17 | const evens = universalSet.createSubset(2, 4); 18 | 19 | const odds = evens.complement(); // 1, 3, 5 20 | ``` 21 | 22 | ### Details 23 | 24 | Introduced in: 0.0.1 25 | 26 | Last updated in: 0.0.1 27 | -------------------------------------------------------------------------------- /docs/difference.md: -------------------------------------------------------------------------------- 1 | # .difference() 2 | 3 | ### Overview 4 | 5 | Returns all of the elements in the first set that are not in the second set. 6 | 7 | `difference(setB: AdvancedSet): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set to find the difference with. Must be an AdvancedSet of the same type as the current set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | const setB = new AdvancedSet(1, 5); 18 | 19 | setA.difference(setB); // AdvancedSet(2, 3, 4) 20 | ``` 21 | 22 | ### Details 23 | 24 | Introduced in: 0.0.1 25 | 26 | Last updated in: 0.0.1 27 | -------------------------------------------------------------------------------- /src/__tests__/Constructor.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An advanced set can take in duplicate values and record only unique entries', () => { 4 | expect(new AdvancedSet(1, 1, 1, 1).toArray()).toMatchObject([1]); 5 | }); 6 | 7 | test('An advanced set can take in multiple different duplicate values and record only unique entries', () => { 8 | expect(new AdvancedSet(1, 2, 2, 3, 3, 3).toArray()).toMatchObject([1, 2, 3]); 9 | }); 10 | 11 | test('An advanced set can take in no parameters and be an empty set', () => { 12 | expect(new AdvancedSet().toArray()).toMatchObject([]); 13 | }); 14 | -------------------------------------------------------------------------------- /docs/foreach.md: -------------------------------------------------------------------------------- 1 | # .forEach() 2 | 3 | ### Overview 4 | 5 | Calls the passed in function once for each element in the set. 6 | 7 | `forEach(forEachFunc: (currVal: T) => R): void` 8 | 9 | ### Parameters 10 | 11 | `forEachFunc` - A callback function that takes in a given element of the set. The result of the function with the current elemnt is not used. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5, 6); 17 | let count = 0; 18 | setA.forEach((x) => (count += x)); 19 | 20 | console.log(count); // 21 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /docs/issubsetof.md: -------------------------------------------------------------------------------- 1 | # .isSubsetOf() 2 | 3 | ### Overview 4 | 5 | Returns if all of the elements of this set are contained in the passed in set. 6 | 7 | `isSubsetOf(setB: AdvancedSet): boolean` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set to check if it contains the current set 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3); 17 | const setB = new AdvancedSet(1, 2, 3, 4, 5); 18 | setA.isSubsetOf(setB); // true 19 | 20 | const setC = new AdvancedSet(2, 3, 4, 5); 21 | setA.isSubsetOf(setC); // false 22 | ``` 23 | 24 | ### Details 25 | 26 | Introduced in: 0.0.1 27 | 28 | Last updated in: 0.0.1 29 | -------------------------------------------------------------------------------- /docs/isdisjointwith.md: -------------------------------------------------------------------------------- 1 | # .isDisjointWith() 2 | 3 | ### Overview 4 | 5 | Returns whether or not the sets share no elements. 6 | 7 | `isDisjointWith(setB: AdvancedSet): boolean` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set to see if no elements are shared with. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5, 6); 17 | const setB = new AdvancedSet(100, 200, 300); 18 | 19 | setA.isDisjointWith(setB); // true 20 | 21 | const setC = new AdvancedSet(1, 2, 10, 20); 22 | 23 | setA.isDisjointWith(setC); // false 24 | ``` 25 | 26 | ### Details 27 | 28 | Introduced in: 0.0.1 29 | 30 | Last updated in: 0.0.1 31 | -------------------------------------------------------------------------------- /docs/issupersetof.md: -------------------------------------------------------------------------------- 1 | # .isSupersetOf() 2 | 3 | ### Overview 4 | 5 | Returns if all of the elements of the passed in set are part of the caller set. 6 | 7 | `isSupersetOf(setB: AdvancedSet): boolean` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set in question of being contained in the caller set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | const setB = new AdvancedSet(1, 2, 3); 18 | setA.isSupersetOf(setB); // true 19 | 20 | const setC = new AdvancedSet(2, 3, 4, 5); 21 | setA.isSupersetOf(setC); // false 22 | ``` 23 | 24 | ### Details 25 | 26 | Introduced in: 0.0.1 27 | 28 | Last updated in: 0.0.1 29 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - [Home](/) 4 | - [add](add.md) 5 | - [clear](clear.md) 6 | - [complement](complement.md) 7 | - [createSubset](createSubset.md) 8 | - [delete](delete.md) 9 | - [difference](difference.md) 10 | - [equals](equals.md) 11 | - [filter](filter.md) 12 | - [forEach](foreach.md) 13 | - [has](has.md) 14 | - [intersection](intersection.md) 15 | - [isDisjointWith](isdisjointwith.md) 16 | - [isEmpty](isempty.md) 17 | - [isSubsetOf](issubsetof.md) 18 | - [isSupersetOf](issupersetof.md) 19 | - [map](map.md) 20 | - [reduce](reduce.md) 21 | - [size](size.md) 22 | - [toArray](toarray.md) 23 | - [toSimpleSet](tosimpleset.md) 24 | - [union](union.md) 25 | -------------------------------------------------------------------------------- /docs/equals.md: -------------------------------------------------------------------------------- 1 | # .equals() 2 | 3 | ### Overview 4 | 5 | Returns if the passed in set has all of the same elements as the current set. 6 | 7 | `equals(otherSet: AdvancedSet): boolean` 8 | 9 | ### Parameters 10 | 11 | `otherSet` - The set to check equality with. Must be an AdvancedSet of the same type as the current set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | const setB = new AdvancedSet(5, 4, 3, 2, 1); 18 | 19 | setA.equals(setB); // true 20 | 21 | const setC = new AdvancedSet(2, 3, 4, 5, 6); 22 | 23 | setA.equals(setC); // false 24 | ``` 25 | 26 | ### Details 27 | 28 | Introduced in: 0.0.1 29 | 30 | Last updated in: 0.0.1 31 | -------------------------------------------------------------------------------- /docs/filter.md: -------------------------------------------------------------------------------- 1 | # .filter() 2 | 3 | ### Overview 4 | 5 | Creates a set with all of the elements that pass the given test function. 6 | 7 | `filter(filterFunc: (currVal: T) => boolean): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `filterFunc` - A function that takes in a given element of the set and returns `true` if the element is to stay in, and `false` if the element is to be thrown out. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5, 6); 17 | const greaterThanTwo = (x: number) => x > 2; 18 | 19 | setA.filter(greaterThanTwo); // AdvancedSet(3, 4, 5, 6) 20 | ``` 21 | 22 | ### Details 23 | 24 | Introduced in: 0.0.1 25 | 26 | Last updated in: 0.0.1 27 | -------------------------------------------------------------------------------- /docs/intersection.md: -------------------------------------------------------------------------------- 1 | # .intersection() 2 | 3 | ### Overview 4 | 5 | Finds the elements that are shared between two sets. 6 | 7 | `intersection(setB: AdvancedSet): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `setB` - The set to find the shared elements between the current set. Must be an AdvancedSet of the same **type**. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5, 6); 17 | const setB = new AdvancedSet(1, 2, 10, 20); 18 | 19 | setA.intersection(setB); // AdvancedSet(1, 2) 20 | 21 | const setC = new AdvancedSet(100, 200, 300); 22 | 23 | setA.intersection(setC); // AdvancedSet() 24 | ``` 25 | 26 | ### Details 27 | 28 | Introduced in: 0.0.1 29 | 30 | Last updated in: 0.0.1 31 | -------------------------------------------------------------------------------- /docs/map.md: -------------------------------------------------------------------------------- 1 | # .map() 2 | 3 | ### Overview 4 | 5 | Returns a new set with results of the passed in function being called with each element in the caller set. 6 | 7 | `map(mapFunc: (currVal: T) => R): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `mapFunc` - The function that each element of the set will be called with. It may return the same type as the original set, or a new type, if the caller wishes to convert the elements of the set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | const timesTen = (x) => x * 10; 18 | 19 | setA.map(timesTen); // AdvancedSet(10, 20, 30, 40, 50) 20 | ``` 21 | 22 | ### Details 23 | 24 | Introduced in: 0.0.1 25 | 26 | Last updated in: 0.0.1 27 | -------------------------------------------------------------------------------- /docs/delete.md: -------------------------------------------------------------------------------- 1 | # .delete() 2 | 3 | ### Overview 4 | 5 | Removes an element from the existing set. Returns the current set (without the new element). 6 | 7 | `delete(val: T): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `val` - The element to remove from the set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 17 | setA.delete(5); // AdvancedSet(1, 2, 3, 4) 18 | 19 | // Original object is changed, as well as the return value 20 | console.log(setA); // AdvancedSet(1, 2, 3, 4) 21 | 22 | // Deleting elements not in the set will simply return the set 23 | setA.delete(5); // AdvancedSet(1, 2, 3, 4) 24 | ``` 25 | 26 | ### Details 27 | 28 | Introduced in: 0.0.1 29 | 30 | Last updated in: 0.0.1 31 | -------------------------------------------------------------------------------- /src/__tests__/Every.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Empty set with a function that returns true should return true', () => { 4 | expect(new AdvancedSet().every((a) => true)).toBe(true); 5 | }); 6 | 7 | test('A non empty set with a function that returns false should return false', () => { 8 | expect(new AdvancedSet(6, 8, 3, 4).every((a) => false)).toBe(false); 9 | }); 10 | 11 | test('A non empty set where not all elements pass the test should return false', () => { 12 | expect(new AdvancedSet(5, 10, 20, 30, -1).every((a) => a >= 0)).toBe(false); 13 | }); 14 | 15 | test('A non empty set where all elements pass the test should return true', () => { 16 | expect(new AdvancedSet(20, 100, 10, 5000).every((x) => x % 10 === 0)).toBe(true); 17 | }); 18 | -------------------------------------------------------------------------------- /docs/reduce.md: -------------------------------------------------------------------------------- 1 | # .reduce() 2 | 3 | ### Overview 4 | 5 | Condenses all of the elements in the set into a single value from the passed in accumulator function. 6 | 7 | `reduce(reduceFunc: (accumulator: R, currVal: T) => R, startingValue: R): R` 8 | 9 | ### Parameters 10 | 11 | `reduceFunc` - A function that takes in the current value of the accumulator, and the current element from the set. It should return the new value for the accumulator. 12 | 13 | `startingValue` - The inital value the accumulator should be. 14 | 15 | ### Usage 16 | 17 | ```js 18 | const setA = new AdvancedSet(1, 2, 3, 4, 5); 19 | const sum = (acc: number, currVal: number) => acc + currVal; 20 | 21 | setA.reduce(sum, 0); // 15 22 | ``` 23 | 24 | ### Details 25 | 26 | Introduced in: 0.0.1 27 | 28 | Last updated in: 0.0.1 29 | -------------------------------------------------------------------------------- /src/__tests__/Complement.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | const universal = new AdvancedSet(5, 10, 15, 20); 4 | 5 | test('Complement of empty set is universal set', () => { 6 | const empty = universal.createSubset(); 7 | expect(empty.complement().toArray()).toMatchObject(universal.toArray()); 8 | }); 9 | 10 | test('Complement of universal set is empty set', () => { 11 | expect(universal.complement().toArray()).toMatchObject([]); 12 | }); 13 | 14 | test('Complement of subset should be other components of universal set', () => { 15 | const subset = universal.createSubset(10, 15); 16 | expect(subset.complement().toArray()).toMatchObject([5, 20]); 17 | }); 18 | 19 | test('Complement of empty universal set is empty set', () => { 20 | expect(new AdvancedSet().createSubset().complement().toArray()).toMatchObject([]); 21 | }); 22 | -------------------------------------------------------------------------------- /src/__tests__/CreateSubset.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Create an empty subset from an empty universal set', () => { 4 | expect(new AdvancedSet().createSubset().toArray()).toMatchObject([]); 5 | }); 6 | 7 | test('Create an empty subset from a non empty universal set', () => { 8 | expect(new AdvancedSet(3, 5, 6).createSubset().toArray()).toMatchObject([]); 9 | }); 10 | 11 | test('Create a non empty subset from a non empty universal set', () => { 12 | expect(new AdvancedSet(10, 20, 30).createSubset(20).toArray()).toMatchObject([20]); 13 | }); 14 | 15 | test('Try to create a subset with elements outside universal set', () => { 16 | const outlier = 10; 17 | expect(() => new AdvancedSet(2, 4, 6, 8).createSubset(outlier)).toThrow( 18 | new Error(`Element ${outlier} is not in the given universal set`), 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/createSubset.md: -------------------------------------------------------------------------------- 1 | # .createSubset() 2 | 3 | ### Overview 4 | 5 | Create a child set branching off of the current set. Allows for a set to use [complement](complement.md), as it now has a parent set. 6 | 7 | `createSubset(...initialValues: T[] | never): AdvancedSet` 8 | 9 | ### Parameters 10 | 11 | `initialValues` - Variable list of items from the set that are to become the subset. Can also be nothing to create an empty subset. Throws an **error** if an element in `initialValues` is not in the parent/universal set. 12 | 13 | ### Usage 14 | 15 | ```js 16 | const universalSet = new AdvancedSet(10, 100, 200, 1000); 17 | 18 | const powersOfTen = universalSet.createSubset(10, 100, 1000); // AdvancedSet(10, 100, 1000) 19 | 20 | const multiplesOfTwo = universalSet.createSubset(2, 200); // Error - 2 is not part of the universal/parent set 21 | ``` 22 | 23 | ### Details 24 | 25 | Introduced in: 0.0.1 26 | 27 | Last updated in: 0.0.1 28 | -------------------------------------------------------------------------------- /src/__tests__/Add.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Add nothing to empty set should be empty set', () => { 4 | expect(new AdvancedSet().add().toArray()).toMatchObject([]); 5 | }); 6 | 7 | test('Empty set adding a value should be a set with just that value', () => { 8 | expect(new AdvancedSet().add(1).toArray()).toMatchObject([1]); 9 | }); 10 | 11 | test('Non emtpy set adding a value should be the set with the new value', () => { 12 | expect(new AdvancedSet(2, 3).add(1).toArray().sort()).toMatchObject([1, 2, 3].sort()); 13 | }); 14 | 15 | test('Non empty set adding nothing should be just that set', () => { 16 | expect(new AdvancedSet(4, 5).add().toArray().sort()).toMatchObject([4, 5].sort()); 17 | }); 18 | 19 | test('Advanced sets should allow for multiple items to be added at the same time', () => { 20 | expect(new AdvancedSet(2, 3, 5).add(1, 4).toArray().sort()).toMatchObject([1, 2, 3, 4, 5].sort()); 21 | }); 22 | -------------------------------------------------------------------------------- /src/__tests__/Iterator.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Iterator should not execute if empty', () => { 4 | const initial = new AdvancedSet(); 5 | let iters = 0; 6 | 7 | for (const item of initial) { 8 | iters++; 9 | } 10 | 11 | expect(iters).toBe(0); 12 | }); 13 | 14 | test('Iterator should execute N times with N items', () => { 15 | let values = [100, 200, 300]; 16 | 17 | const initial = new AdvancedSet(...values); 18 | 19 | let iters = 0; 20 | 21 | for (const item of initial) { 22 | iters++; 23 | } 24 | 25 | expect(iters).toBe(values.length); 26 | }); 27 | 28 | test('Iterator should contain items in AdvancedSet', () => { 29 | let values = [100, 200, 300]; 30 | 31 | const initial = new AdvancedSet(...values); 32 | 33 | let output = []; 34 | 35 | for (const item of initial) { 36 | output.push(item); 37 | } 38 | 39 | expect(new AdvancedSet(...initial).equals(new AdvancedSet(...output))).toBe(true); 40 | }); -------------------------------------------------------------------------------- /src/__tests__/IsDisjointWith.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | // I think this is the case, but it'd be great if someone can verify it 4 | test('Empty set is dijoint with itself', () => { 5 | expect(new AdvancedSet().isDisjointWith(new AdvancedSet())).toBe(true); 6 | }); 7 | 8 | test('Empty set is disjoint with a non empty set', () => { 9 | expect(new AdvancedSet().isDisjointWith(new AdvancedSet('Disjoint'))).toBe(true); 10 | }); 11 | 12 | test('Non empty set is disjoint with empty set', () => { 13 | expect(new AdvancedSet(4, 10, 20).isDisjointWith(new AdvancedSet())).toBe(true); 14 | }); 15 | 16 | test('A non empty set is not disjoint with another empty set if they share some elements', () => { 17 | expect(new AdvancedSet(1, 2, 3).isDisjointWith(new AdvancedSet(3, 4, 5))).toBe(false); 18 | }); 19 | 20 | test('A non empty set is disjoint with another set when they share no elements', () => { 21 | expect(new AdvancedSet(1, 5, 10).isDisjointWith(new AdvancedSet(11, 15, 110))).toBe(true); 22 | }); 23 | -------------------------------------------------------------------------------- /src/__tests__/Some.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An empty set with a function that returns true should return false', () => { 4 | expect(new AdvancedSet().some((el) => true)).toBe(false); 5 | }); 6 | 7 | test('A non empty set with a function returning false should return false', () => { 8 | const setA = new AdvancedSet(1, 5, 10); 9 | 10 | expect(setA.some(() => false)).toBe(false); 11 | expect(setA.some(() => true)).toBe(true); 12 | }); 13 | 14 | test('A non empty set with a function no elements meet should return false', () => { 15 | const setA = new AdvancedSet('learning', 'to', 'fly'); 16 | const lenOverTen = (a: string) => a.length > 10; 17 | 18 | expect(setA.some(lenOverTen)).toBe(false); 19 | }); 20 | 21 | test('A non empty set with a function that some elements meet should return true', () => { 22 | const setA = new AdvancedSet('drive', 'my', 'car'); 23 | const containsA = (x: string) => x.includes('a'); 24 | 25 | expect(setA.some(containsA)).toBe(true); 26 | }); 27 | -------------------------------------------------------------------------------- /src/__tests__/ForEach.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An empty set using foreach with any function should *return* nothing', () => { 4 | expect(new AdvancedSet().forEach((x) => x + 1)).toBe(undefined); 5 | }); 6 | 7 | test('A non empty set using foreach with any function should *return* nothing', () => { 8 | expect(new AdvancedSet(1, 5, 10).forEach((a) => a + 1)).toBe(undefined); 9 | }); 10 | 11 | test('An empty array incrementing an outside counter with foreach should not increase the counter', () => { 12 | let count = 0; 13 | expect(new AdvancedSet().forEach((x) => (count += x))).toBe(undefined); 14 | expect(count).toBe(0); 15 | }); 16 | 17 | test('A non empty array incrementing an outside counter with foreach should increase the counter', () => { 18 | let count = 0; 19 | const testSet = new AdvancedSet('300', '12', '4'); 20 | const addString = (a: string) => (count += parseInt(a)); 21 | expect(testSet.forEach(addString)).toBe(undefined); 22 | expect(count).toBe(316); 23 | }); 24 | -------------------------------------------------------------------------------- /src/__tests__/Filter.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Filter an empty set with any function should return an empty set', () => { 4 | expect(new AdvancedSet().filter(() => true).toArray()).toMatchObject([]); 5 | }); 6 | 7 | test("Filter a non empty set with a 'true' function should return the same set", () => { 8 | expect(new AdvancedSet(1, 3, 5).filter(() => true).toArray()).toMatchObject([1, 3, 5]); 9 | }); 10 | 11 | test("Filter a non empty set with a 'false' function should return an empty set", () => { 12 | expect(new AdvancedSet(1, 3, 5).filter(() => false).toArray()).toMatchObject([]); 13 | }); 14 | 15 | test('Filter set of 1-10 for evens should return even numbers', () => { 16 | const evens = [2, 4, 6, 8, 10]; 17 | expect(new AdvancedSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).filter((x) => x % 2 === 0).toArray()).toMatchObject(evens); 18 | }); 19 | 20 | test('Filter on condition that nothing meets should return empty set', () => { 21 | expect(new AdvancedSet(2, 4, 5).filter((x) => x === 1).toArray()).toMatchObject([]); 22 | }); 23 | -------------------------------------------------------------------------------- /src/__tests__/Intersection.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | const basicSet = new AdvancedSet(1, 3, 5, 7); 4 | 5 | test('Intersection with an empty set', () => { 6 | const intersection = basicSet.intersection(new AdvancedSet()); 7 | expect(intersection.toArray()).toEqual([]); 8 | }); 9 | 10 | test('Intersection with the same set', () => { 11 | const intersection = basicSet.intersection(basicSet); 12 | expect(intersection.toArray()).toEqual(basicSet.toArray()); 13 | }); 14 | 15 | test('Intersection with different set - some shared elements', () => { 16 | const intersection = basicSet.intersection(new AdvancedSet(3, 5)); 17 | expect(intersection.toArray()).toEqual([3, 5]); 18 | }); 19 | 20 | test('Intersection with different set - no shared elements', () => { 21 | const intersection = basicSet.intersection(new AdvancedSet(0, 2, 4, 6, 8)); 22 | expect(intersection.toArray()).toEqual([]); 23 | }); 24 | 25 | test('Intersection of empty set with empty set', () => { 26 | expect(new AdvancedSet().intersection(new AdvancedSet()).toArray()).toEqual([]); 27 | }); 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Sets 2 | 3 | A JS/TS library that builds extra functionality on top of the standard `Set()` 4 | 5 | ```ts 6 | const setA = new AdvancedSet(1, 2, 4); 7 | const setB = new AdvancedSet(2, 4, 6, 8); 8 | 9 | setA.intersection(setB); // AdvancedSet(2, 4) 10 | setA.union(setB); // AdvancedSet(1, 2, 4, 6, 8) 11 | setA.toArray(); // [1, 2, 4] 12 | 13 | const universal = new AdvancedSet('TS', 'Advanced', 'Sets'); 14 | const sub = universal.createSubset('TS'); 15 | const complement = sub.complement(); // AdvancedSet("Advanced", "Sets") 16 | 17 | setA.filter((a) => a > 1); // AdvancedSet(2, 4) 18 | setA.map((x) => x * 2); // AdvancedSet(2, 4, 8) 19 | 20 | setA.add(5); // AdvancedSet(1, 2, 4, 5) 21 | ``` 22 | 23 | ## Installation 24 | 25 | ``` 26 | npm i advanced-sets 27 | ``` 28 | 29 | ## Documentation 30 | 31 | https://jpbulman.github.io/Advanced-Sets/ 32 | 33 | ## Local Setup 34 | 35 | First, clone the repository and cd into the folder. Then, install all of the dependencies with 36 | 37 | ``` 38 | npm install 39 | ``` 40 | 41 | Run the test suite with 42 | 43 | ``` 44 | npm test 45 | ``` 46 | -------------------------------------------------------------------------------- /src/__tests__/Equals.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An empty set should equal a different empty set', () => { 4 | expect(new AdvancedSet().equals(new AdvancedSet())).toBe(true); 5 | }); 6 | 7 | test('An empty set should not equal a different non empty set', () => { 8 | expect(new AdvancedSet().equals(new AdvancedSet(1, 2))).toBe(false); 9 | }); 10 | 11 | test('A non empty set should not equal an empty set', () => { 12 | expect(new AdvancedSet(4, 5).equals(new AdvancedSet())).toBe(false); 13 | }); 14 | 15 | test('A non empty set with some different elements from another set should not be equal to the other set', () => { 16 | expect(new AdvancedSet(1, 7, 10).equals(new AdvancedSet(7, 20, 50))).toBe(false); 17 | }); 18 | 19 | test('A subset and a superset should not be equal if they are different in size', () => { 20 | expect(new AdvancedSet(1, 2, 3).equals(new AdvancedSet(1, 2, 3, 4))).toBe(false); 21 | }); 22 | 23 | test('A non empty set should be equal to a new set with the same elements', () => { 24 | expect(new AdvancedSet(0, -4, 30).equals(new AdvancedSet(30, -4, 0))).toBe(true); 25 | }); 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 JP Bulman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/__tests__/Map.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Mapping an empty set with any function should return an empty set', () => { 4 | expect(new AdvancedSet().map(() => 1).toArray()).toMatchObject([]); 5 | }); 6 | 7 | test('Mapping a non empty set with a one to one function should return a set of the same length', () => { 8 | expect(new AdvancedSet(1, 2, 3).map((x) => x * 3).toArray()).toMatchObject([3, 6, 9]); 9 | }); 10 | 11 | test('Mapping a non empty set with a function that creates duplicate entries should return a smaller set', () => { 12 | expect(new AdvancedSet(4, 10, 900).map(() => true).toArray()).toMatchObject([true]); 13 | }); 14 | 15 | test('Mapping a non empty set with a function to create duplicate entries', () => { 16 | expect( 17 | new AdvancedSet('four', 'four', 'six').map((x: string) => (x === 'four' ? 'six' : x)).toArray(), 18 | ).toMatchObject(['six']); 19 | }); 20 | 21 | test('Mapping a non empty set with type changes', () => { 22 | expect( 23 | new AdvancedSet('1', '40', '3') 24 | .map((x: string) => parseInt(x)) 25 | .toArray() 26 | .sort(), 27 | ).toMatchObject([1, 40, 3].sort()); 28 | }); 29 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Sets 2 | 3 | Advanced Sets is a JS/TS library that builds extra functionality on top of the standard `Set()` 4 | 5 | ## Basic Operations 6 | 7 | ```js 8 | const setA = new AdvancedSet(1, 2, 4); 9 | const setB = new AdvancedSet(2, 4, 6, 8); 10 | 11 | setA.intersection(setB); // AdvancedSet(2, 4) 12 | setA.union(setB); // AdvancedSet(1, 2, 4, 6, 8) 13 | setA.toArray(); // [1, 2, 4] 14 | 15 | const universal = new AdvancedSet('TS', 'Advanced', 'Sets'); 16 | const sub = universal.createSubset('TS'); 17 | const complement = sub.complement(); // AdvancedSet("Advanced", "Sets") 18 | 19 | setA.filter((a) => a > 1); // AdvancedSet(2, 4) 20 | setA.map((x) => x * 2); // AdvancedSet(2, 4, 8) 21 | 22 | setA.add(5); // AdvancedSet(1, 2, 4, 5) 23 | ``` 24 | 25 | ## Chaining Allows for easy Functional Programming 26 | 27 | ```js 28 | const setA = new AdvancedSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 29 | const setB = new AdvancedSet(10, 100, 50); 30 | 31 | setA 32 | .map((x) => x * 10) 33 | .intersection(setB) 34 | .filter((x) => x > 10) 35 | .union(new AdvancedSet(5)) 36 | .reduce((acc, curr) => acc + curr); // 115 37 | ``` 38 | 39 | ## Installation 40 | 41 | ``` 42 | npm i advanced-sets 43 | ``` 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "advanced-sets", 3 | "version": "0.0.2", 4 | "description": "A JS/TS library that expands upon the functionality of Sets", 5 | "main": "lib/AdvancedSet.js", 6 | "types": "lib/AdvancedSet.d.ts", 7 | "scripts": { 8 | "test": "jest --config jestconfig.json", 9 | "build": "tsc", 10 | "format": "prettier --write \"src/**/*.ts\"", 11 | "lint": "tslint -p tsconfig.json", 12 | "prepare": "npm run build", 13 | "prepublishOnly": "npm test && npm run lint", 14 | "preversion": "npm run lint", 15 | "version": "npm run format && git add -A src", 16 | "postversion": "git push && git push --tags" 17 | }, 18 | "keywords": [ 19 | "advanced", 20 | "sets", 21 | "intersection", 22 | "union", 23 | "complement", 24 | "subset", 25 | "superset" 26 | ], 27 | "author": "JP Bulman ", 28 | "license": "ISC", 29 | "devDependencies": { 30 | "@types/jest": "^26.0.19", 31 | "jest": "^26.6.3", 32 | "prettier": "^2.2.1", 33 | "ts-jest": "^26.4.4", 34 | "tslint": "^6.1.3", 35 | "tslint-config-prettier": "^1.18.0", 36 | "typescript": "^4.1.3" 37 | }, 38 | "files": [ 39 | "lib/**/*" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /src/__tests__/Difference.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('Difference of an empty set with an empty set should be an empty set', () => { 4 | expect(new AdvancedSet().difference(new AdvancedSet()).isEmpty()).toBe(true); 5 | }); 6 | 7 | test('Difference of an empty set with a non empty set should be an empty set', () => { 8 | expect(new AdvancedSet().difference(new AdvancedSet()).isEmpty()).toBe(true); 9 | }); 10 | 11 | test('Difference of a non empty set with an empty set should be the non empty set', () => { 12 | const setA = new AdvancedSet(8, 6, 7, 5); 13 | expect(setA.difference(new AdvancedSet()).toArray()).toMatchObject(setA.toArray()); 14 | }); 15 | 16 | test('Differnce of a non empty set with itself should be empty', () => { 17 | const setA = new AdvancedSet(4, 9, 10); 18 | expect(setA.difference(setA).isEmpty()).toBe(true); 19 | }); 20 | 21 | test('Difference of two different sets should be the items that are in the first, without the items in both', () => { 22 | const setA = new AdvancedSet(1, 2, 3); 23 | const setB = new AdvancedSet(2, 4, 5, 6); 24 | expect(setA.difference(setB).toArray().sort()).toMatchObject([1, 3].sort()); 25 | expect(setB.difference(setA).toArray().sort()).toMatchObject([4, 5, 6].sort()); 26 | }); 27 | -------------------------------------------------------------------------------- /src/__tests__/Reduce.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | const sum = (acc: number, curr: number) => acc + curr; 4 | 5 | test('Reduce with an empty set and an empty function should return 0', () => { 6 | expect(new AdvancedSet().reduce(() => 1, 0)).toBe(0); 7 | }); 8 | 9 | test('Reduce with an empty set and an add funciton should return 0', () => { 10 | expect(new AdvancedSet().reduce(sum, 0)).toBe(0); 11 | }); 12 | 13 | test('Reduce with an empty set and a sum function with a different inital value should return the initial value', () => { 14 | expect(new AdvancedSet().reduce(sum, 5)).toBe(5); 15 | }); 16 | 17 | test('Reduce with a non empty set, but with an empty function should return 0', () => { 18 | expect(new AdvancedSet(4, 5, 10).reduce(() => 0, 0)).toBe(0); 19 | }); 20 | 21 | test('Reduce with a non empty set and a sum function should return the sum of the set', () => { 22 | expect(new AdvancedSet(2, 4, 8, -1).reduce(sum, 0)).toBe(13); 23 | }); 24 | 25 | test('Reduce with a non empty set and a sum functinon with a non zero starting value should return the sum plus the initial value', () => { 26 | expect(new AdvancedSet(10, 20, 30).reduce(sum, 5)).toBe(65); 27 | }); 28 | 29 | test('Reduce with changing types', () => { 30 | expect(new AdvancedSet('234', '-1', '20').reduce((acc: number, currVal: string) => acc + parseInt(currVal), 0)).toBe( 31 | 253, 32 | ); 33 | }); 34 | -------------------------------------------------------------------------------- /src/__tests__/IsSubsetOf.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('The empty set is a subset of the empty set', () => { 4 | expect(new AdvancedSet().isSubsetOf(new AdvancedSet())).toBe(true); 5 | }); 6 | 7 | test('The empty set is a subset of a non empty set', () => { 8 | expect(new AdvancedSet().isSubsetOf(new AdvancedSet(10))).toBe(true); 9 | }); 10 | 11 | test('A non empty set is not a subset of an empty set', () => { 12 | expect(new AdvancedSet('US', 'ET', 'GB').isSubsetOf(new AdvancedSet())).toBe(false); 13 | }); 14 | 15 | test('A non empty set is not a subset of a non empty set when they share no elements', () => { 16 | expect(new AdvancedSet('all', 'your', 'base').isSubsetOf(new AdvancedSet('belong', 'to', 'us'))).toBe(false); 17 | }); 18 | 19 | test('A non empty set should not be a subset of a non emtpy set where they share some elements, but the first set has elements the latter set', () => { 20 | const setA = new AdvancedSet(2, 4, 6); 21 | const setB = new AdvancedSet(1, 2, 3, 4, 5); 22 | expect(setA.isSubsetOf(setB)).toBe(false); 23 | }); 24 | 25 | test("A non empty set should be a subset of a non empty set where all of the first set's elements are in the second set", () => { 26 | const setA = new AdvancedSet('For', 'Once'); 27 | const setB = new AdvancedSet('For', 'I', 'In', 'Once'); 28 | expect(setA.isSubsetOf(setB)).toBe(true); 29 | }); 30 | 31 | test('A non empty subset is a subset of itself', () => { 32 | const setA = new AdvancedSet(1, 4, 6); 33 | expect(setA.isSubsetOf(setA)).toBe(true); 34 | }); 35 | -------------------------------------------------------------------------------- /src/__tests__/IsSuperSetOf.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('The empty set is a super set of the empty set', () => { 4 | expect(new AdvancedSet().isSupersetOf(new AdvancedSet())).toBe(true); 5 | }); 6 | 7 | test('The empty set is not a super set of any non empty set', () => { 8 | expect(new AdvancedSet().isSupersetOf(new AdvancedSet(12))).toBe(false); 9 | }); 10 | 11 | test('Any non empty set is a super set of the empty set', () => { 12 | expect(new AdvancedSet(3, 91, 3, 5).isSupersetOf(new AdvancedSet())).toBe(true); 13 | }); 14 | 15 | test('A non empty set is not a super set of a non empty set where no elements are shared', () => { 16 | const setA = new AdvancedSet('Planes', 'Trains', 'Automobiles'); 17 | const setB = new AdvancedSet('1987', 'John', 'Hughes'); 18 | expect(setA.isSupersetOf(setB)).toBe(false); 19 | }); 20 | 21 | test('A non empty set is not a super set of a non empty set where some, but not all, elements of the first set are in the second set', () => { 22 | const setA = new AdvancedSet(-3, 1, 4, 1); 23 | const setB = new AdvancedSet(3, 1, 4, 1, 5); 24 | expect(setB.isSupersetOf(setA)).toBe(false); 25 | }); 26 | 27 | test('A non empty set is a super set of a non empty set where all of the elements in the second set are in the first set', () => { 28 | const setA = new AdvancedSet('Sheep', 'Wood', 'Rock'); 29 | const setB = new AdvancedSet('Sheep', 'Wood', 'Wheat', 'Rock', 'Brick'); 30 | expect(setB.isSupersetOf(setA)).toBe(true); 31 | }); 32 | 33 | test('A non empty set is a super set of itself', () => { 34 | const setA = new AdvancedSet('Rocket', 'Man'); 35 | expect(setA.isSupersetOf(setA)).toBe(true); 36 | }); 37 | -------------------------------------------------------------------------------- /src/__tests__/Union.test.ts: -------------------------------------------------------------------------------- 1 | import AdvancedSet from '../AdvancedSet'; 2 | 3 | test('An empty set union with another empty set should be an empty set', () => { 4 | expect(new AdvancedSet().union(new AdvancedSet()).toArray()).toMatchObject([]); 5 | }); 6 | 7 | test('An empty set union with a non empty set should be that non empty set', () => { 8 | const empty = new AdvancedSet(); 9 | const nonEmpty = new AdvancedSet(5, 6, 10); 10 | expect(nonEmpty.union(empty).toArray()).toMatchObject([5, 6, 10]); 11 | // Reflexive property 12 | expect(empty.union(nonEmpty).toArray()).toMatchObject([5, 6, 10]); 13 | }); 14 | 15 | test('A non empty set union with itself is itself', () => { 16 | const arr = ['foo', 'bar', 'baz']; 17 | const nonEmpty = new AdvancedSet(...arr); 18 | expect(nonEmpty.union(nonEmpty).toArray()).toMatchObject(arr); 19 | }); 20 | 21 | test('If Set A and Set B have no shared components, then their union should be a set of all of their components', () => { 22 | const setA = new AdvancedSet(5, 0, 9); 23 | const setB = new AdvancedSet(10, 12, 13); 24 | expect(setA.union(setB).toArray().sort()).toMatchObject([0, 5, 9, 10, 12, 13].sort()); 25 | }); 26 | 27 | test('If Set A and Set B share some parts, their union should a set of their shared parts and their distinct parts', () => { 28 | const setA = new AdvancedSet(-100, 200, 1000); 29 | const setB = new AdvancedSet(-1000, 200, 100); 30 | expect(setA.union(setB).toArray().sort()).toMatchObject([-1000, -100, 100, 200, 1000].sort()); 31 | }); 32 | 33 | test('Set unions should be able to be chained', () => { 34 | const setA = new AdvancedSet(20, -1); 35 | const setB = new AdvancedSet(1, 30); 36 | const setC = new AdvancedSet(2, 40); 37 | expect(setA.union(setB).union(setC).toArray().sort()).toMatchObject([-1, 1, 2, 20, 30, 40].sort()); 38 | }); 39 | -------------------------------------------------------------------------------- /src/AdvancedSet.ts: -------------------------------------------------------------------------------- 1 | export default class AdvancedSet { 2 | // The underlying set 3 | private _set: Set = new Set(); 4 | // The parent, or 'universal', set. This is defined when a child is created with 'createSubSet()' 5 | private _universalSet?: AdvancedSet = undefined; 6 | 7 | constructor(...initialValues: T[] | never) { 8 | for (const val of initialValues) { 9 | this._set.add(val); 10 | } 11 | } 12 | 13 | public has(val: T): boolean { 14 | return this._set.has(val); 15 | } 16 | 17 | public add(...vals: T[]): AdvancedSet { 18 | for (const val of vals) this._set.add(val); 19 | return this; 20 | } 21 | 22 | public delete(val: T): AdvancedSet { 23 | this._set.delete(val); 24 | return this; 25 | } 26 | 27 | public clear(): AdvancedSet { 28 | this._set.clear(); 29 | return this; 30 | } 31 | 32 | public get size(): number { 33 | return this._set.size; 34 | } 35 | 36 | public toSimpleSet(): Set { 37 | return this._set; 38 | } 39 | 40 | // public static Ø() {} 41 | 42 | /* 43 | * Returns a new set containing the shared elements between this set and the given parameter set 44 | */ 45 | public intersection(setB: AdvancedSet): AdvancedSet { 46 | let smallest: AdvancedSet = setB; 47 | let other: AdvancedSet = this; 48 | 49 | if (this.size < setB.size) { 50 | smallest = this; 51 | other = setB; 52 | } 53 | 54 | return new AdvancedSet(...smallest.toArray().filter((x) => other.has(x))); 55 | } 56 | 57 | public toArray(): T[] { 58 | return Array.from(this._set); 59 | } 60 | 61 | public complement(): AdvancedSet { 62 | if (this._universalSet) { 63 | return new AdvancedSet(...this._universalSet.toArray().filter((x) => !this._set.has(x))); 64 | } else { 65 | const empty = new AdvancedSet(); 66 | empty._universalSet = this; 67 | return empty; 68 | } 69 | } 70 | 71 | public createSubset(...initialValues: T[] | never): AdvancedSet { 72 | // Make sure all of the values are inside the universal set 73 | for (const i of initialValues) { 74 | if (!this._set.has(i)) { 75 | throw new Error(`Element ${i} is not in the given universal set`); 76 | } 77 | } 78 | 79 | const newSet = new AdvancedSet(...initialValues); 80 | // Set the child's parent to the current set 81 | newSet._universalSet = this; 82 | return newSet; 83 | } 84 | 85 | public filter(filterFunc: (currVal: T) => boolean): AdvancedSet { 86 | return new AdvancedSet(...this.toArray().filter(filterFunc)); 87 | } 88 | 89 | public map(mapFunc: (currVal: T) => R): AdvancedSet { 90 | return new AdvancedSet(...this.toArray().map(mapFunc)); 91 | } 92 | 93 | public reduce(reduceFunc: (accumulator: R, currVal: T) => R, startingValue: R): R { 94 | return this.toArray().reduce(reduceFunc, startingValue); 95 | } 96 | 97 | public forEach(forEachFunc: (currVal: T) => R): void { 98 | this._set.forEach((val) => { 99 | forEachFunc(val); 100 | }); 101 | } 102 | 103 | public equals(otherSet: AdvancedSet): boolean { 104 | if (otherSet.size !== this.size) return false; 105 | for (const x of otherSet) { 106 | if (!this.has(x)) return false; 107 | } 108 | return true; 109 | } 110 | 111 | public isEmpty(): boolean { 112 | return this.size === 0; 113 | } 114 | 115 | public union(setB: AdvancedSet): AdvancedSet { 116 | return new AdvancedSet(...this.toArray(), ...setB.toArray()); 117 | } 118 | 119 | public difference(setB: AdvancedSet): AdvancedSet { 120 | return this.filter((a) => !setB.has(a)); 121 | } 122 | 123 | public isSubsetOf(setB: AdvancedSet): boolean { 124 | return this.filter((a) => setB.has(a)).size === this.size; 125 | } 126 | 127 | public isSupersetOf(setB: AdvancedSet): boolean { 128 | return setB.isSubsetOf(this); 129 | } 130 | 131 | public isDisjointWith(setB: AdvancedSet): boolean { 132 | return this.intersection(setB).isEmpty(); 133 | } 134 | 135 | [Symbol.iterator]() { 136 | let index = -1; 137 | let data = this.toArray(); 138 | 139 | return { 140 | next: () => ({ 141 | value: data[++index], 142 | done: index === this.size, 143 | }), 144 | }; 145 | } 146 | 147 | public some(test: (x: T) => boolean): boolean { 148 | return this.toArray().some(test); 149 | } 150 | 151 | public every(test: (x: T) => boolean): boolean { 152 | return this.toArray().every(test); 153 | } 154 | 155 | // partialSubset, isProperSubsetOf, isProperSupersetOf, multi set intersection, 156 | // power sets, subset by function 157 | } 158 | --------------------------------------------------------------------------------