( comparator: (a: V1Type, b: V1Type) => number, options?: TopKOptions, )
| 57 | * @returns A piped operator that orders the elements and limits the number of results |
| 58 | */ |
| 59 | export function topKWithIndex< |
| 60 | KType extends T extends KeyValue<infer K, infer _V> ? K : never, |
| 61 | V1Type extends T extends KeyValue<KType, infer V> ? V : never, |
| 62 | T, |
| 63 | >( |
| 64 | comparator: (a: V1Type, b: V1Type) => number, |
| 65 | options?: TopKOptions, |
| 66 | ): PipedOperator<T, KeyValue<KType, [V1Type, number]>> { |
| 67 | const limit = options?.limit ?? Infinity |
| 68 | const offset = options?.offset ?? 0 |
| 69 | |
| 70 | return ( |
| 71 | stream: IStreamBuilder<T>, |
| 72 | ): IStreamBuilder<KeyValue<KType, [V1Type, number]>> => { |
| 73 | const reduced = stream.pipe( |
| 74 | reduce<KType, V1Type, [V1Type, number], T>((values) => { |
| 75 | // `values` is a list of tuples, first element is the value, second is the multiplicity |
| 76 | const consolidated = new MultiSet(values).consolidate() |
| 77 | let i = offset |
| 78 | const sortedValues = consolidated |
| 79 | .getInner() |
| 80 | .sort((a, b) => comparator(a[0], b[0])) |
| 81 | .slice(offset, offset + limit) |
| 82 | .map(([value, multiplicity]): [[V1Type, number], number] => [ |
| 83 | [value, i++], |
| 84 | multiplicity, |
| 85 | ]) |
| 86 | return sortedValues |
| 87 | }), |
| 88 | ) |
| 89 | return reduced |
| 90 | } |
| 91 | } |
no test coverage detected