feat: align some methods with the Set Methods proposal (#8890)

feat(collection): align/add methods with/from Set Methods proposal

BREAKING CHANGE: The `intersect` method has been renamed to `intersection`
BREAKING CHANGE: The `difference` method has been renamed to `symmetricDifference`
BREAKING CHANGE: The `subtract` method has been renamed to `difference`
This commit is contained in:
Almeida 2023-11-07 18:04:51 +00:00 committed by GitHub
parent 054eaec7d7
commit 3b8df63a5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 59 deletions

View file

@ -116,16 +116,15 @@ describe('combineEntries() tests', () => {
});
describe('difference() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2]);
const coll2 = createTestCollection();
const diff = createCollectionFrom(['c', 3]);
const coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);
const coll2 = createCollectionFrom(['b', 2], ['d', 4], ['e', 5]);
test('it removes entries from the bigger collection on the right', () => {
expect(coll1.difference(coll2)).toStrictEqual(diff);
test('it returns the difference the collections', () => {
expect(coll1.difference(coll2)).toStrictEqual(createCollectionFrom(['a', 1], ['c', 3]));
});
test('removes the difference from the bigger collection on the left', () => {
expect(coll2.difference(coll1)).toStrictEqual(diff);
test('it returns the difference the collections from the opposite order', () => {
expect(coll2.difference(coll1)).toStrictEqual(createCollectionFrom(['d', 4], ['e', 5]));
});
});
@ -407,12 +406,12 @@ describe('hasAny() tests', () => {
});
});
describe('intersect() tests', () => {
describe('intersection() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2]);
const coll2 = createCollectionFrom(['a', 1], ['c', 3]);
test('it returns a new collection', () => {
const c = coll1.intersect(coll2);
test('it returns the intersection of the collections', () => {
const c = coll1.intersection(coll2);
expect(c).toBeInstanceOf(Collection);
expect(c.size).toStrictEqual(1);
@ -776,19 +775,6 @@ describe('sort() tests', () => {
});
});
describe('subtract() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3], ['d', undefined]);
const coll2 = createCollectionFrom(['b', 2], ['c', 0]);
test('it returns a new collection', () => {
const c = coll1.subtract(coll2);
expect(c).toBeInstanceOf(Collection);
expect(c.size).toStrictEqual(3);
expect(c).toStrictEqual(createCollectionFrom(['a', 1], ['c', 3], ['d', undefined]));
});
});
describe('sweep() test', () => {
const coll = createTestCollection();
@ -816,6 +802,17 @@ describe('sweep() test', () => {
});
});
describe('symmetricDifference() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);
const coll2 = createCollectionFrom(['b', 2], ['d', 4], ['e', 5]);
test('it returns the symmetric difference of the collections', () => {
expect(coll1.symmetricDifference(coll2)).toStrictEqual(
createCollectionFrom(['a', 1], ['c', 3], ['d', 4], ['e', 5]),
);
});
});
describe('tap() tests', () => {
const coll = createTestCollection();
@ -845,6 +842,19 @@ describe('toJSON() tests', () => {
});
});
describe('union() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2]);
const coll2 = createCollectionFrom(['a', 1], ['c', 3]);
test('it returns the union of the collections', () => {
const c = coll1.union(coll2);
expect(c).toBeInstanceOf(Collection);
expect(c.size).toStrictEqual(3);
expect(c).toStrictEqual(createCollectionFrom(['a', 1], ['b', 2], ['c', 3]));
});
});
describe('random thisArg tests', () => {
const coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]) as Collection<string, unknown>;

View file

@ -751,48 +751,71 @@ export class Collection<K, V> extends Map<K, V> {
}
/**
* The intersect method returns a new structure containing items where the keys and values are present in both original structures.
* The intersection method returns a new collection containing the items where the key is present in both collections.
*
* @param other - The other Collection to filter against
* @example
* ```ts
* const col1 = new Collection([['a', 1], ['b', 2]]);
* const col2 = new Collection([['a', 1], ['c', 3]]);
* const intersection = col1.intersection(col2);
* console.log(col1.intersection(col2));
* // => Collection { 'a' => 1 }
* ```
*/
public intersect<T>(other: ReadonlyCollection<K, T>): Collection<K, T> {
const coll = new this.constructor[Symbol.species]<K, T>();
for (const [key, value] of other) {
if (this.has(key) && Object.is(value, this.get(key))) {
coll.set(key, value);
}
}
return coll;
}
/**
* The subtract method returns a new structure containing items where the keys and values of the original structure are not present in the other.
*
* @param other - The other Collection to filter against
*/
public subtract<T>(other: ReadonlyCollection<K, T>): Collection<K, V> {
const coll = new this.constructor[Symbol.species]<K, V>();
for (const [key, value] of this) {
if (!other.has(key) || !Object.is(value, other.get(key))) {
coll.set(key, value);
}
}
return coll;
}
/**
* The difference method returns a new structure containing items where the key is present in one of the original structures but not the other.
*
* @param other - The other Collection to filter against
*/
public difference<T>(other: ReadonlyCollection<K, T>): Collection<K, T | V> {
public intersection<T>(other: ReadonlyCollection<K, T>): Collection<K, T | V> {
const coll = new this.constructor[Symbol.species]<K, T | V>();
for (const [key, value] of other) {
if (!this.has(key)) coll.set(key, value);
for (const [key, value] of this) {
if (other.has(key)) coll.set(key, value);
}
return coll;
}
/**
* Returns a new collection containing the items where the key is present in either of the collections.
*
* @remarks
*
* If the collections have any items with the same key, the value from the first collection will be used.
* @param other - The other Collection to filter against
* @example
* ```ts
* const col1 = new Collection([['a', 1], ['b', 2]]);
* const col2 = new Collection([['a', 1], ['b', 3], ['c', 3]]);
* const union = col1.union(col2);
* console.log(union);
* // => Collection { 'a' => 1, 'b' => 2, 'c' => 3 }
* ```
*/
public union<T>(other: ReadonlyCollection<K, T>): Collection<K, T | V> {
const coll = new this.constructor[Symbol.species]<K, T | V>(this);
for (const [key, value] of other) {
if (!coll.has(key)) coll.set(key, value);
}
return coll;
}
/**
* Returns a new collection containing the items where the key is present in this collection but not the other.
*
* @param other - The other Collection to filter against
* @example
* ```ts
* const col1 = new Collection([['a', 1], ['b', 2]]);
* const col2 = new Collection([['a', 1], ['c', 3]]);
* console.log(col1.difference(col2));
* // => Collection { 'b' => 2 }
* console.log(col2.difference(col1));
* // => Collection { 'c' => 3 }
* ```
*/
public difference<T>(other: ReadonlyCollection<K, T>): Collection<K, V> {
const coll = new this.constructor[Symbol.species]<K, V>();
for (const [key, value] of this) {
if (!other.has(key)) coll.set(key, value);
}
@ -800,6 +823,33 @@ export class Collection<K, V> extends Map<K, V> {
return coll;
}
/**
* Returns a new collection containing only the items where the keys are present in either collection, but not both.
*
* @param other - The other Collection to filter against
* @example
* ```ts
* const col1 = new Collection([['a', 1], ['b', 2]]);
* const col2 = new Collection([['a', 1], ['c', 3]]);
* const symmetricDifference = col1.symmetricDifference(col2);
* console.log(col1.symmetricDifference(col2));
* // => Collection { 'b' => 2, 'c' => 3 }
* ```
*/
public symmetricDifference<T>(other: ReadonlyCollection<K, T>): Collection<K, T | V> {
const coll = new this.constructor[Symbol.species]<K, T | V>();
for (const [key, value] of this) {
if (!other.has(key)) coll.set(key, value);
}
for (const [key, value] of other) {
if (!this.has(key)) coll.set(key, value);
}
return coll;
}
/**
* Merges two Collections together into a new Collection.
*