Wrap *iterable* and return an object that buckets the iterable into child iterables based on a *key* function. >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3'] >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character >>> sorted(list(s)) # Get the
| 76 | |
| 77 | # Copied from more_itertools 10.3 |
| 78 | class bucket: |
| 79 | """Wrap *iterable* and return an object that buckets the iterable into |
| 80 | child iterables based on a *key* function. |
| 81 | |
| 82 | >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3'] |
| 83 | >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character |
| 84 | >>> sorted(list(s)) # Get the keys |
| 85 | ['a', 'b', 'c'] |
| 86 | >>> a_iterable = s['a'] |
| 87 | >>> next(a_iterable) |
| 88 | 'a1' |
| 89 | >>> next(a_iterable) |
| 90 | 'a2' |
| 91 | >>> list(s['b']) |
| 92 | ['b1', 'b2', 'b3'] |
| 93 | |
| 94 | The original iterable will be advanced and its items will be cached until |
| 95 | they are used by the child iterables. This may require significant storage. |
| 96 | |
| 97 | By default, attempting to select a bucket to which no items belong will |
| 98 | exhaust the iterable and cache all values. |
| 99 | If you specify a *validator* function, selected buckets will instead be |
| 100 | checked against it. |
| 101 | |
| 102 | >>> from itertools import count |
| 103 | >>> it = count(1, 2) # Infinite sequence of odd numbers |
| 104 | >>> key = lambda x: x % 10 # Bucket by last digit |
| 105 | >>> validator = lambda x: x in {1, 3, 5, 7, 9} # Odd digits only |
| 106 | >>> s = bucket(it, key=key, validator=validator) |
| 107 | >>> 2 in s |
| 108 | False |
| 109 | >>> list(s[2]) |
| 110 | [] |
| 111 | |
| 112 | """ |
| 113 | |
| 114 | def __init__(self, iterable, key, validator=None): |
| 115 | self._it = iter(iterable) |
| 116 | self._key = key |
| 117 | self._cache = defaultdict(deque) |
| 118 | self._validator = validator or (lambda x: True) |
| 119 | |
| 120 | def __contains__(self, value): |
| 121 | if not self._validator(value): |
| 122 | return False |
| 123 | |
| 124 | try: |
| 125 | item = next(self[value]) |
| 126 | except StopIteration: |
| 127 | return False |
| 128 | else: |
| 129 | self._cache[value].appendleft(item) |
| 130 | |
| 131 | return True |
| 132 | |
| 133 | def _get_values(self, value): |
| 134 | """ |
| 135 | Helper to yield items from the parent iterator that match *value*. |
no outgoing calls
no test coverage detected
searching dependent graphs…