| 12 | * A multiset of data. |
| 13 | */ |
| 14 | export class MultiSet<T> { |
| 15 | #inner: MultiSetArray<T> |
| 16 | |
| 17 | constructor(data: MultiSetArray<T> = []) { |
| 18 | this.#inner = data |
| 19 | } |
| 20 | |
| 21 | toString(indent = false): string { |
| 22 | return `MultiSet(${JSON.stringify(this.#inner, null, indent ? 2 : undefined)})` |
| 23 | } |
| 24 | |
| 25 | toJSON(): string { |
| 26 | return JSON.stringify(Array.from(this.getInner())) |
| 27 | } |
| 28 | |
| 29 | static fromJSON<U>(json: string): MultiSet<U> { |
| 30 | return new MultiSet(JSON.parse(json)) |
| 31 | } |
| 32 | |
| 33 | /** |
| 34 | * Apply a function to all records in the collection. |
| 35 | */ |
| 36 | map<U>(f: (data: T) => U): MultiSet<U> { |
| 37 | return new MultiSet( |
| 38 | this.#inner.map(([data, multiplicity]) => [f(data), multiplicity]), |
| 39 | ) |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * Filter out records for which a function f(record) evaluates to False. |
| 44 | */ |
| 45 | filter(f: (data: T) => boolean): MultiSet<T> { |
| 46 | return new MultiSet(this.#inner.filter(([data, _]) => f(data))) |
| 47 | } |
| 48 | |
| 49 | /** |
| 50 | * Negate all multiplicities in the collection. |
| 51 | */ |
| 52 | negate(): MultiSet<T> { |
| 53 | return new MultiSet( |
| 54 | this.#inner.map(([data, multiplicity]) => [data, -multiplicity]), |
| 55 | ) |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Concatenate two collections together. |
| 60 | */ |
| 61 | concat(other: MultiSet<T>): MultiSet<T> { |
| 62 | const out: MultiSetArray<T> = [] |
| 63 | chunkedArrayPush(out, this.#inner) |
| 64 | chunkedArrayPush(out, other.getInner()) |
| 65 | return new MultiSet(out) |
| 66 | } |
| 67 | |
| 68 | /** |
| 69 | * Produce as output a collection that is logically equivalent to the input |
| 70 | * but which combines identical instances of the same record into one |
| 71 | * (record, multiplicity) pair. |
nothing calls this directly
no outgoing calls
no test coverage detected