UNPKG

@rimbu/multimap

Version:

An immutable Map where each key can have multiple values

826 lines (816 loc) 29.9 kB
import type { RMap, RSet, VariantMap, VariantSet, } from '@rimbu/collection-types'; import type { KeyValue, WithKeyValue, } from '@rimbu/collection-types/map-custom'; import type { ArrayNonEmpty, OptLazy, RelatedTo, ToJSON, TraverseState, } from '@rimbu/common'; import type { FastIterable, Reducer, Stream, StreamSource, Streamable, } from '@rimbu/stream'; export interface VariantMultiMapBase< K, V, Tp extends VariantMultiMapBase.Types = VariantMultiMapBase.Types, > extends FastIterable<[K, V]> { /** * Returns true if the collection is empty. * @example * ```ts * HashMultiMapHashValue.empty<number>().isEmpty // => true * HashMultiMapHashValue.of([1, 1], [2, 2]).isEmpty // => false * ``` */ readonly isEmpty: boolean; /** * Returns the number of keys in the collection. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).keySize // => 2 * HashMultiMapHashValue.of([1, 1], [1, 2]).keySize // => 1 * ``` */ readonly keySize: number; /** * Returns the number of unique key-value combinations in this collection. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).size // => 2 * HashMultiMapHashValue.of([1, 1], [1, 2]).size // => 2 * ``` */ readonly size: number; /** * Returns the Map representation of this collection. * @example * ```ts * const m = HashMultiMapHashValue.of([1, 1], [2, 2]) * const map: HashMap<number, HashSet.NonEmpty<number>> = m.keyMap * ``` */ readonly keyMap: WithKeyValue<Tp, K, V>['keyMap']; /** * Returns the collection as a .NonEmpty type * @throws RimbuError.EmptyCollectionAssumedNonEmptyError if the collection is empty * @example * ```ts * HashMultiMapHashValue.empty<number, number>().assumeNonEmpty() // => throws * const m: HashMultiMapHashValue<number, number> = HashMultiMapHashValue.of([1, 1], [2, 2]) * const m2: HashMultiMapHashValue.NonEmpty<number, number> = m // => compiler error * const m3: HashMultiMapHashValue.NonEmpty<number, number> = m.assumeNonEmpty() * ``` * @note returns reference to this collection */ assumeNonEmpty(): WithKeyValue<Tp, K, V>['nonEmpty']; /** * Returns true if there is at least one entry in the collection, and instructs the compiler to treat the collection * as a .NonEmpty type. * @example * ```ts * const m: HashMultiMapHashValue<number, number> = HashMap.of([1, 1], [2, 2]) * m.stream().first(0) // compiler allows fallback value since the Stream may be empty * if (m.nonEmpty()) { * m.stream().first(0) // compiler error: fallback value not allowed since Stream is not empty * } * ``` */ nonEmpty(): this is WithKeyValue<Tp, K, V>['nonEmpty']; /** * Returns a Stream containing all entries of this collection as tuples of key and value. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).stream().toArray() // => [[1, 1], [2, 2]] * ``` */ stream(): Stream<[K, V]>; /** * Returns a Stream containing all keys of this collection. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b']]).streamKeys().toArray() // => [1, 2] * ``` */ streamKeys(): Stream<K>; /** * Returns a Stream containing all values of this collection. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b']]).streamValues().toArray() // => ['a', 'b'] * ``` */ streamValues(): Stream<V>; /** * Returns true if the given `key` is present in the collection. * @param key - the key to look for * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']) * m.hasKey(2) // => true * m.hasKey(3) // => false * ``` */ hasKey<UK = K>(key: RelatedTo<K, UK>): boolean; /** * Returns true if the given `key` has the given `value` as one of its values in the collection. * @param key - the key to look for * @param value - the value to look for * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']) * m.hasEntry(1, 'a') // => true * m.hasEntry(1, 'b') // => false * ``` */ hasEntry<UK = K>(key: RelatedTo<K, UK>, value: V): boolean; /** * Returns the value collection associated to the given `key`. * @param key - the key to look for * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']) * m.getValues(1).toArray() // => ['a'] * m.getValues(10).toArray() // => [] * ``` */ getValues<UK = K>( key: RelatedTo<K, UK> ): WithKeyValue<Tp, K, V>['keyMapValues']; /** * Returns the collection where the values associated with given `key` are removed. * @param key - the key of the entries to remove * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) * m.removeKey(2).toArray() // => [[1, 'a'], [1, 'c']] * m.removeKey(3) === m // true * ``` * @note guarantees same object reference if the key is not present */ removeKey<UK = K>(key: RelatedTo<K, UK>): WithKeyValue<Tp, K, V>['normal']; /** * Returns the collection where the values associated with given `keys` are removed. * @param keys - a `StreamSource` of keys to remove * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) * m.removeKeys([2, 10]).toArray() // => [[1, 'a'], [1, 'c']] * m.removeKeys([10, 11]) === m // true * ``` * @note guarantees same object reference if the key is not present */ removeKeys<UK = K>( keys: StreamSource<RelatedTo<K, UK>> ): WithKeyValue<Tp, K, V>['normal']; /** * Returns the collection where given `value` if removed from the values associated with given `key`. * @param key - the key of the entry to remove * @param value - the value of the entry to remove * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) * m.removeEntry(2, 'b').toArray() // => [[1, 'a'], [1, 'c']] * m.removeEntry(2, 'q').toArray() // => [[1, 'a'], [2, 'b'], [1, 'c']] * m.removeEntry(3, 'a') === m // true * ``` * @note guarantees same object reference if the key is not present */ removeEntry<UK = K, UV = V>( key: RelatedTo<K, UK>, value: RelatedTo<V, UV> ): WithKeyValue<Tp, K, V>['normal']; /** * Returns the collection where given `entries` are removed. * @param entries - a `StreamSource` containing key-value entries to remove * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) * m.removeEntries([[2, 'b'], [1, 'd']]).toArray() // => [[1, 'a'], [1, 'c']] * m.removeEntries([2, 'q']).toArray() // => [[1, 'a'], [2, 'b'], [1, 'c']] * m.removeEntries(3) === m // true * ``` * @note guarantees same object reference if the key is not present */ removeEntries<UK = K, UV = V>( entries: StreamSource<[RelatedTo<K, UK>, RelatedTo<V, UV>]> ): WithKeyValue<Tp, K, V>['normal']; /** * Returns a tuple containing the collection of which the given `key` is removed, and the values that * are associated with that key. If the key is not present, it will return undefined instead. * @param key - the key of the entry to remove * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']) * const result = m.removeKeyAndGet(2) * if (result !== undefined) console.log([result[0].toString(), result[1]]) // => logs [HashMultiMapHashValue(1 => 'a'), HashSet('b')] * console.log(m.removeKeyAndGet(3)) // => logs undefined * ``` */ removeKeyAndGet<UK = K>( key: RelatedTo<K, UK> ): | [ WithKeyValue<Tp, K, V>['normal'], WithKeyValue<Tp, K, V>['keyMapValuesNonEmpty'], ] | undefined; /** * Performs given function `f` for each entry of the collection, using given `state` as initial traversal state. * @param f - the function to perform for each element, receiving:<br/> * - `entry`: the next tuple of a key and value<br/> * - `index`: the index of the element<br/> * - `halt`: a function that, if called, ensures that no new elements are passed * @param state - (optional) the traverse state * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).forEach((entry, i, halt) => { * console.log([entry[1], entry[0]]); * if (i >= 1) halt(); * }) * // => logs ['a', 1] ['c', 1] (or other order) * ``` * @note O(N) */ forEach( f: (entry: [K, V], index: number, halt: () => void) => void, options?: { state?: TraverseState } ): void; /** * Returns a collection containing only those entries that satisfy given `pred` predicate. * @param pred - a predicate function receiving:<br/> * - `entry`: the next entry<br/> * - `index`: the entry index<br/> * - `halt`: a function that, when called, ensures no next entries are passed * @param options - (optional) an object containing the following properties:<br/> * - negate: (default: false) when true will negate the predicate * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) * .filter(entry => entry[0] === 2 || entry[1] === 'c') * .toArray() * // => [[2, 'b'], [1, 'c']] * ``` */ filter( pred: (entry: [K, V], index: number, halt: () => void) => boolean, options?: { negate?: boolean } ): WithKeyValue<Tp, K, V>['normal']; /** * Returns an array containing all entries in this collection. * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toArray() // => [[1, 'a'], [1, 'c'], [2, 'b']] * ``` * @note O(log(N)) * @note it is safe to mutate the returned array, however, the array elements are not copied, thus should be treated as read-only */ toArray(): [K, V][]; /** * Returns a string representation of this collection. * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toString() * // => HashMultiMapHashValue(1 => ['a', 'c'], 2 => ['b']) * ``` */ toString(): string; /** * Returns a JSON representation of this collection. * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toJSON() * // => { dataType: 'HashMultiMapHashValue', value: [[1, ['a', 'c']], [2, ['b']]] } * ``` */ toJSON(): ToJSON<[K, V[]][]>; } export namespace VariantMultiMapBase { export interface NonEmpty< K, V, Tp extends VariantMultiMapBase.Types = VariantMultiMapBase.Types, > extends VariantMultiMapBase<K, V, Tp>, Streamable.NonEmpty<[K, V]> { /** * Returns false since this collection is known to be non-empty * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).isEmpty // => false * ``` */ readonly isEmpty: false; /** * Returns the non-empty Map representation of this collection. * @example * ```ts * const m = HashMultiMapHashValue.of([1, 1], [2, 2]) * const map: HashMap.NonEmpty<number, HashSet.NonEmpty<number>> = m.keyMap * ``` */ readonly keyMap: WithKeyValue<Tp, K, V>['keyMapNonEmpty']; /** * Returns a self reference since this collection is known to be non-empty. * @example * ```ts * const m = HashMultiMapHashValue.of([1, 1], [2, 2]); * m === m.assumeNonEmpty() // => true * ``` */ assumeNonEmpty(): this; /** * Returns this collection typed as a 'possibly empty' collection. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).asNormal(); // type: HashMultiMapHashValue<number, number> * ``` */ asNormal(): WithKeyValue<Tp, K, V>['normal']; /** * Returns true since this collection is known to be non-empty * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).nonEmpty() // => true * ``` */ nonEmpty(): this is WithKeyValue<Tp, K, V>['nonEmpty']; /** * Returns a non-empty Stream containing all entries of this collection as tuples of key and value. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).stream().toArray() // => [[1, 1], [2, 2]] * ``` */ stream(): Stream.NonEmpty<[K, V]>; /** * Returns a non-empty Stream containing all keys of this collection. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b']]).streamKeys().toArray() // => [1, 2] * ``` */ streamKeys(): Stream.NonEmpty<K>; /** * Returns a non-empty Stream containing all values of this collection. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b']]).streamValues().toArray() // => ['a', 'b'] * ``` */ streamValues(): Stream.NonEmpty<V>; /** * Returns a non-empty array containing all entries in this collection. * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toArray() // => [[1, 'a'], [1, 'c'], [2, 'b']] * ``` * @note O(log(N)) * @note it is safe to mutate the returned array, however, the array elements are not copied, thus should be treated as read-only */ toArray(): ArrayNonEmpty<[K, V]>; } /** * Utility interface that provides higher-kinded types for this collection. */ export interface Types extends KeyValue { readonly normal: VariantMultiMapBase<this['_K'], this['_V']>; readonly nonEmpty: VariantMultiMapBase.NonEmpty<this['_K'], this['_V']>; readonly keyMapValues: VariantSet<this['_V']>; readonly keyMapValuesNonEmpty: VariantSet.NonEmpty<this['_V']>; readonly keyMap: VariantMap<this['_K'], VariantSet.NonEmpty<this['_V']>>; readonly keyMapNonEmpty: VariantMap.NonEmpty< this['_K'], VariantSet.NonEmpty<this['_V']> >; } } export interface MultiMapBase< K, V, Tp extends MultiMapBase.Types = MultiMapBase.Types, > extends VariantMultiMapBase<K, V, Tp> { /** * Returns the `context` associated to this collection instance. */ readonly context: WithKeyValue<Tp, K, V>['context']; /** * Returns the collection with the given `value` added to the given `key` values. * @param key - the key for which to add a value * @param value - the value to add to the key values * @example * ```ts * HashMultiMapHashValue.of([1, 'a']).add(2, 'b').toArray() // => [[1, 'a'], [2, 'b']] * HashMultiMapHashValue.of([1, 'a']).add(1, 'b').toArray() // => [[1, 'a'], [1, 'b']] * ``` */ add(key: K, value: V): WithKeyValue<Tp, K, V>['nonEmpty']; /** * Returns the collection with the given `entries` added. * @param entries - a `StreamSource` containing entries to add * @example * ```ts * HashMultiMapHashValue.of([1, 'a']).addEntries([[2, 'b'], [1, 'c']).toArray() * // => [[1, 'a'], [1, 'c'], [2, 'b']] * ``` */ addEntries( entries: StreamSource.NonEmpty<readonly [K, V]> ): WithKeyValue<Tp, K, V>['nonEmpty']; addEntries( entries: StreamSource<readonly [K, V]> ): WithKeyValue<Tp, K, V>['normal']; /** * Returns the collection where given `key` has the given `values` associated with it. * @param key - the key for which to set the values * @param values - the values to set for the key * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b']).setValues(1, ['d', 'e']).toArray() * // => [[1, 'd'], [1, 'e'], [2, 'b']] * ``` */ setValues( key: K, values: StreamSource.NonEmpty<V> ): WithKeyValue<Tp, K, V>['nonEmpty']; setValues(key: K, values: StreamSource<V>): WithKeyValue<Tp, K, V>['normal']; /** * Returns the collection with the given `atKey` key modified according to given `options`. * @param atKey - the key at which to modify the collection * @param options - an object containing the following information:<br/> * - ifNew: (optional) if the given `atKey` is not present in the collection, this value or function will be used * to generate new values. If a function returning the token argument is given, no new entry is created.<br/> * - ifExists: (optional) if given `atKey` exists in the collection, this function is called with the current values to * return new values. As a second argument, a `remove` token is given. If the function returns this token, the current * entry is removed. * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']) * m.modifyAt(3, { ifNew: ['c', 'd'] }).toArray() * // => [[1, 'a'], [2, 'b'], [3, 'c'], [3, 'd']] * m.modifyAt(3, { ifNew: () => 1 < 2 ? [] : ['c'] }).toArray() * // => [[1, 'a'], [2, 'b']] * m.modifyAt(2, { ifExists: () => ['c'] }).toArray() * // => [[1, 'a'], [2, 'c']] * m.modifyAt(2, { ifExists: (v) => v.add('d') }).toArray() * // => [[1, 'a'], [2, 'c'], [2, 'd']] * m.modifyAt(2, { ifExists: (v) => v.has('a') ? v : [] }).toArray() * // => [[1, 'a']] * ``` */ modifyAt( atKey: K, options: { ifNew?: OptLazy<StreamSource<V>>; ifExists?: | (( currentValues: WithKeyValue<Tp, K, V>['keyMapValuesNonEmpty'] ) => StreamSource<V>) | StreamSource<V>; } ): WithKeyValue<Tp, K, V>['normal']; /** * Returns a builder object containing the entries of this collection. * @example * ```ts * const builder: HashMultiMapHashValue.Builder<number, string> * = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [2, 'c']).toBuilder() * ``` */ toBuilder(): WithKeyValue<Tp, K, V>['builder']; } export namespace MultiMapBase { export interface NonEmpty< K, V, Tp extends MultiMapBase.Types = MultiMapBase.Types, > extends VariantMultiMapBase.NonEmpty<K, V, Tp>, Omit< MultiMapBase<K, V, Tp>, keyof VariantMultiMapBase.NonEmpty<any, any, any> >, Streamable.NonEmpty<[K, V]> { /** * Returns a non-empty Stream containing all entries of this collection as tuples of key and value. * @example * ```ts * HashMultiMapHashValue.of([1, 1], [2, 2]).stream().toArray() // => [[1, 1], [2, 2]] * ``` */ stream(): Stream.NonEmpty<[K, V]>; /** * Returns the collection with the given `entries` added. * @param entries - a `StreamSource` containing entries to add * @example * ```ts * HashMultiMapHashValue.of([1, 'a']).addEntries([[2, 'b'], [1, 'c']).toArray() * // => [[1, 'a'], [1, 'c'], [2, 'b']] * ``` */ addEntries( entries: StreamSource<readonly [K, V]> ): WithKeyValue<Tp, K, V>['nonEmpty']; } export interface Factory< Tp extends MultiMapBase.Types, UK = unknown, UV = unknown, > { /** * Returns the (singleton) empty instance of this type and context with given key and value types. * @example * ```ts * HashMultiMapHashValue.empty<number, string>() // => HashMultiMapHashValue<number, string> * HashMultiMapHashValue.empty<string, boolean>() // => HashMultiMapHashValue<string, boolean> * ``` */ empty<K extends UK, V extends UV>(): WithKeyValue<Tp, K, V>['normal']; /** * Returns an immutable multimap of this collection type and context, containing the given `entries`. * @param entries - a non-empty array of key-value entries * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']) // => HashMap.NonEmpty<number, string> * ``` */ of<K extends UK, V extends UV>( ...entries: ArrayNonEmpty<readonly [K, V]> ): WithKeyValue<Tp, K, V>['nonEmpty']; /** * Returns an immutable multimap of this type and context, containing the entries in the given `source` `StreamSource`. * @param sources - an array of `StreamSource` instances containing key-value entries * @example * ```ts * HashMultiMapHashValue.from([[1, 'a'], [2, 'b']]) // => HashMultiMapHashValue.NonEmpty<number, string> * ``` */ from<K extends UK, V extends UV>( ...sources: ArrayNonEmpty<StreamSource.NonEmpty<readonly [K, V]>> ): WithKeyValue<Tp, K, V>['nonEmpty']; from<K extends UK, V extends UV>( ...sources: ArrayNonEmpty<StreamSource<readonly [K, V]>> ): WithKeyValue<Tp, K, V>['normal']; /** * Returns an empty builder instance for this type of collection and context. * @example * ```ts * HashMultiMapHashValue.builder<number, string>() // => HashMultiMapHashValue.Builder<number, string> * ``` */ builder<K extends UK, V extends UV>(): WithKeyValue<Tp, K, V>['builder']; /** * Returns a `Reducer` that adds received tuples to a MultiMap and returns the MultiMap as a result. When a `source` is given, * the reducer will first create a MultiMap from the source, and then add tuples to it. * @param source - (optional) an initial source of tuples to add to * @example * ```ts * const someSource: [number, string][] = [1, 'a'], [2, 'b']; * const result = Stream.of([1, 'c'], [3, 'a']).reduce(SortedMultiMap.reducer(someSource)) * result.toArray() // => [[1, 'a'], [1, 'c'], [2, 'b'], [3, 'a']] * ``` * @note uses a builder under the hood. If the given `source` is a BiMap in the same context, it will directly call `.toBuilder()`. */ reducer<K extends UK, V extends UV>( source?: StreamSource<readonly [K, V]> ): Reducer<readonly [K, V], WithKeyValue<Tp, K, V>['normal']>; } /** * The multimap's Context instance that serves as a factory for all related immutable instances and builders. */ export interface Context< UK, UV, Tp extends MultiMapBase.Types = MultiMapBase.Types, > extends MultiMapBase.Factory<Tp, UK, UV> { /** * A string tag defining the specific collection type * @example * ```ts * HashMultiMapHashValue.defaultContext().typeTag // => 'HashMultiMapHashValue' * ``` */ readonly typeTag: string; /** * The context used for the internal keymap instances. */ readonly keyMapContext: WithKeyValue<Tp, UK, UV>['keyMapContext']; readonly keyMapValuesContext: WithKeyValue< Tp, UK, UV >['keyMapValuesContext']; } export interface Builder< K, V, Tp extends MultiMapBase.Types = MultiMapBase.Types, > { /** * Returns the amount of entries in the builder. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b'], [1, 'c']]).toBuilder().size * // => 3 * ``` */ readonly size: number; /** * Returns true if there are no entries in the builder. * @example * ```ts * HashMultiMapHashValue.of([[1, 'a'], [2, 'b']]).toBuilder().isEmpty * // => false * ``` */ readonly isEmpty: boolean; /** * Returns a built immutable collection of the values asssociated with given `key` * @param key - the key for which to get the associated values * @example * ```ts * const m = HashMultiMapHashValue.of([[1, 'a'], [2, 'b'], [1, 'c']]).toBuilder() * m.getValues(1).toArray() // => ['a', 'c'] * m.getValues(10).toArray() // => [] * ``` */ getValues<UK = K>( key: RelatedTo<K, UK> ): WithKeyValue<Tp, K, V>['keyMapValues']; /** * Assigns given `values` `StreamSource` to the given `key`, replacing potential existing * values, and removing the key if `values` is empty. * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.setValues(1, ['a']) // => false * m.setValues(2, ['c', 'd']) // => true * ``` */ setValues(key: K, values: StreamSource<V>): boolean; /** * Returns true if the given `key` is present in the builder. * @param key - the key to look for * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.hasKey(2) // => true * m.hasKey(3) // => false * ``` */ hasKey<UK = K>(key: RelatedTo<K, UK>): boolean; /** * Returns true if the given `value` is associated with given `key` in the builder. * @param key - the key to look for * @param value - the value to look for * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.hasEntry(2, 'b') // => true * m.hasEntry(2, 'c') // => false * m.hasEntry(3, 'a') // => false * ``` */ hasEntry<UK = K>(key: RelatedTo<K, UK>, value: V): boolean; /** * Adds an entry with given `key` and `value` to the builder. * @param key - the entry key * @param value - the entry value * @returns true if the data in the builder has changed * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.add(1, 'a') // => false * m.add(1, 'b') // => true * ``` */ add(key: K, value: V): boolean; /** * Adds given `entries` to the builder. * @param entries - a `StreamSource` containig entries to add * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.addEntries([1, 'a'], [2, 'b']]) // => false * m.addEntries([1, 'b'], [2, 'd']]) // => true * ``` */ addEntries(entries: StreamSource<readonly [K, V]>): boolean; /** * Removes the given `value` from the values associated with given `key` from the builder. * @param key - the key at which to remove the value * @param value - the value to remove * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toBuilder() * m.removeEntry(3, 'a') // => false * m.removeEntry(1, 'a') // => true * ``` */ removeEntry<UK = K, UV = V>( key: RelatedTo<K, UK>, value: RelatedTo<V, UV> ): boolean; /** * Removes the given `entries` from the builder. * @param entries - a `StreamSource` containing entries to remove * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * m.removeEntries([[3, 'a'], [3, 'b']]) // => false * m.removeEntries([[1, 'a'], [3, 'b']]) // => true * ``` */ removeEntries<UK = K, UV = V>( entries: StreamSource<[RelatedTo<K, UK>, RelatedTo<V, UV>]> ): boolean; /** * Removes the values associated with given `key` from the builder. * @param key - the key of which to remove all values * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toBuilder() * m.removeKey(3) // => false * m.removeKey(1) // => true * ``` */ removeKey<UK = K>(key: RelatedTo<K, UK>): boolean; /** * Removes the values associated with each key of the given `keys` * @param keys - a `StreamSource` of keys for which to remove all values * @returns true if the data in the builder has changed * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toBuilder() * m.removeKeys([10, 11]) // => false * m.removeKeys([1]) // => true * ``` */ removeKeys<UK = K>(keys: StreamSource<RelatedTo<K, UK>>): boolean; /** * Performs given function `f` for each entry of the builder, using given `state` as initial traversal state. * @param f - the function to perform for each element, receiving:<br/> * - `entry`: the next tuple of a key and value<br/> * - `index`: the index of the element<br/> * - `halt`: a function that, if called, ensures that no new elements are passed * @param state - (optional) the traverse state * @throws RibuError.ModifiedBuilderWhileLoopingOverItError if the builder is modified while * looping over it * @example * ```ts * HashMultiMapHashValue.of([1, 'a'], [2, 'b'], [1, 'c']).toBuilder().forEach((entry, i, halt) => { * console.log([entry[1], entry[0]]); * if (i >= 1) halt(); * }) * // => logs ['a', 1] ['c', 1] (or other order) * ``` * @note O(N) */ forEach( f: (entry: [K, V], index: number, value: () => void) => void, options?: { state?: TraverseState } ): void; /** * Returns an immutable collection instance containing the entries in this builder. * @example * ```ts * const m = HashMultiMapHashValue.of([1, 'a'], [2, 'b']).toBuilder() * const m2: HashMultiMapHashValue<number, string> = m.build() * ``` */ build(): WithKeyValue<Tp, K, V>['normal']; } /** * Utility interface that provides higher-kinded types for this collection. */ export interface Types extends VariantMultiMapBase.Types { readonly normal: MultiMapBase<this['_K'], this['_V']>; readonly nonEmpty: MultiMapBase.NonEmpty<this['_K'], this['_V']>; readonly context: MultiMapBase.Context<this['_K'], this['_V']>; readonly builder: MultiMapBase.Builder<this['_K'], this['_V']>; readonly keyMap: RMap<this['_K'], RSet.NonEmpty<this['_V']>>; readonly keyMapNonEmpty: RMap.NonEmpty< this['_K'], RSet.NonEmpty<this['_V']> >; readonly keyMapContext: RMap.Context<this['_K']>; readonly keyMapValuesContext: RSet.Context<this['_V']>; readonly keyMapValues: RSet<this['_V']>; readonly keyMapValuesNonEmpty: RSet.NonEmpty<this['_V']>; } }