|
| 1 | +import { TTransIteratorSyncOrAsync } from "../../types.js"; |
| 2 | +/** |
| 3 | + * This operator should make it easy to distribute different categories on the input iterator, |
| 4 | + * to multiple child iterators for further processing per category. |
| 5 | + * The child iterator depends on the 'category' that is determined by the first element |
| 6 | + * of the tuple. |
| 7 | + * |
| 8 | + * Imagine things like: I need to calculate the averages 'per schoolyear'. |
| 9 | + * That would mean, categorize per schoolyear, and then calculate the average |
| 10 | + * of the inner iterators by using a map after distribute. |
| 11 | + * |
| 12 | + * If you are not going to use all output iterators, make sure to filter out |
| 13 | + * the categories you don't need before using distribute, because otherwise an unused |
| 14 | + * buffer will be held needlessly in memory. |
| 15 | + * |
| 16 | + * The category is compared using simple equality checks, so strings and numbers are an easy fit. |
| 17 | + * If you need more complex categories (like an array), make sure to return the same instance |
| 18 | + * as the category. (Maybe we should create a 'categorize' or 'groupBy' operator that |
| 19 | + * can help with dealing with more complex categories?) |
| 20 | + * |
| 21 | + * Questions: |
| 22 | + * - Imagine you use it to categorize http requests (for example by sender ip/port), |
| 23 | + * how do we 'close' a channel after a while so we can avoid the memory to keep growing? |
| 24 | + * I mean, after some time you'll assume that the same 'sender' has done, and the output terator's |
| 25 | + * next() call should return { done: true }. Would that be a setting, |
| 26 | + * like the (unfinished) 'abandoned timeout' in the 'multiIterable' operator? |
| 27 | + * - It could make sense to create a version that can handle multiple categories per value. |
| 28 | + * Like for instance: divisible by 2, divisible by 3, divisible by 5, etc. |
| 29 | + * where some values can be in multiple categories. |
| 30 | + * This could also be done by making a categorize operator that can produce multiple tuples |
| 31 | + * for each input, which would keep this operator simple. |
| 32 | + * |
| 33 | + * ``` |
| 34 | + * ┌───────────────────────────────────────────────────────────┐ |
| 35 | + * │input iterator with tuples of the form [ category, value ] | |
| 36 | + * └──────┬────────────────────────────────────────────────────┘ |
| 37 | + * │ |
| 38 | + * ┌──────▼───────────────────────┐ |
| 39 | + * │ output iterator of iterators │ |
| 40 | + * │ (1 next() for each category) │ |
| 41 | + * └──────────────────────────────┘ |
| 42 | + * ├─────────────────────────────┐────────────────────── ... |
| 43 | + * │ │ |
| 44 | + * ┌────▼─────────────────────┐ ┌────▼─────────────────────┐ |
| 45 | + * │ [ category 1, iterator ] │ │ [ category 2, iterator ] │ |
| 46 | + * └────┬─────────────────────┘ └──────────────────────────┘ |
| 47 | + * │ |
| 48 | + * │ |
| 49 | + * ┌──────▼──────────────────────────┐ |
| 50 | + * │ forEach([ cetegory, iterator ]) │ |
| 51 | + * └─────────────────────────────────┘ |
| 52 | + * | |
| 53 | + * ↳ pipe( iterator, ) |
| 54 | + * ``` |
| 55 | + * |
| 56 | + * @example |
| 57 | + * ```typescript |
| 58 | + * await pipe( |
| 59 | + * itr8ange(1, 1000), |
| 60 | + * map( (v) => [ v % 2 === 0 ? 'even' : 'odd', v ] as [string, number] ), // add the category to the value |
| 61 | + * // adding the category first allows us to easily filter out categories we don't need |
| 62 | + * distribute(), |
| 63 | + * map(([category, iterator]) => ({ |
| 64 | + * category, |
| 65 | + * values: pipe( |
| 66 | + * iterator, |
| 67 | + * take(2), |
| 68 | + * toArray, |
| 69 | + * ), |
| 70 | + * })), |
| 71 | + * itr8ToArray, |
| 72 | + * ) |
| 73 | + * // => [ |
| 74 | + * // { category: 'odd', values: [ 1, 3 ] }, |
| 75 | + * // { category: 'even', values: [ 2, 4 ] }, |
| 76 | + * // ] |
| 77 | + * ``` |
| 78 | + * |
| 79 | + * @category operators/general |
| 80 | + */ |
| 81 | +declare function distribute<T, C = unknown>(): TTransIteratorSyncOrAsync<[ |
| 82 | + C, |
| 83 | + T |
| 84 | +], [ |
| 85 | + C, |
| 86 | + IterableIterator<T> | AsyncIterableIterator<T> |
| 87 | +]>; |
| 88 | +export { distribute }; |
0 commit comments