iterquarry 2.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iterquarry-2.1.1/LICENSE +21 -0
- iterquarry-2.1.1/PKG-INFO +482 -0
- iterquarry-2.1.1/README.md +455 -0
- iterquarry-2.1.1/pyproject.toml +53 -0
- iterquarry-2.1.1/setup.cfg +4 -0
- iterquarry-2.1.1/src/iterquarry/__init__.py +373 -0
- iterquarry-2.1.1/src/iterquarry/augment.py +130 -0
- iterquarry-2.1.1/src/iterquarry/combine.py +231 -0
- iterquarry-2.1.1/src/iterquarry/combo.py +353 -0
- iterquarry-2.1.1/src/iterquarry/concurrency.py +65 -0
- iterquarry-2.1.1/src/iterquarry/grouping.py +366 -0
- iterquarry-2.1.1/src/iterquarry/lookahead.py +166 -0
- iterquarry-2.1.1/src/iterquarry/numeric.py +253 -0
- iterquarry-2.1.1/src/iterquarry/other.py +209 -0
- iterquarry-2.1.1/src/iterquarry/recipes.py +599 -0
- iterquarry-2.1.1/src/iterquarry/select.py +381 -0
- iterquarry-2.1.1/src/iterquarry/summarize.py +292 -0
- iterquarry-2.1.1/src/iterquarry/windowing.py +105 -0
- iterquarry-2.1.1/src/iterquarry/wrapping.py +196 -0
- iterquarry-2.1.1/src/iterquarry.egg-info/PKG-INFO +482 -0
- iterquarry-2.1.1/src/iterquarry.egg-info/SOURCES.txt +23 -0
- iterquarry-2.1.1/src/iterquarry.egg-info/dependency_links.txt +1 -0
- iterquarry-2.1.1/src/iterquarry.egg-info/requires.txt +3 -0
- iterquarry-2.1.1/src/iterquarry.egg-info/top_level.txt +1 -0
- iterquarry-2.1.1/tests/test_behavior.py +466 -0
iterquarry-2.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 iterquarry contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iterquarry
|
|
3
|
+
Version: 2.1.1
|
|
4
|
+
Summary: Python iterable tools: pairwise, chunked batches, sliding windows, flatten, sampling, and combinatorics.
|
|
5
|
+
Author: iterquarry contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://pypi.org/project/iterquarry/
|
|
8
|
+
Keywords: iterable,iterator,itertools,pairwise,chunked,sliding window,flatten,windowed,sampling,combinatorics,permutations,batches
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: test
|
|
25
|
+
Requires-Dist: pytest; extra == "test"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# iterquarry
|
|
29
|
+
|
|
30
|
+
`iterquarry` is a Python library of extra tools for working with iterables. It sits beside the standard-library `itertools` module and covers the jobs that come up once a loop is no longer enough: fixed-size batches, sliding windows, lookahead, flattening nested data, sampling, combinatorics, and small numeric helpers.
|
|
31
|
+
|
|
32
|
+
The public functions are plain callables. Import the names you need:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from iterquarry import pairwise, chunked, windowed
|
|
36
|
+
|
|
37
|
+
list(pairwise("ABCDE"))
|
|
38
|
+
# [('A', 'B'), ('B', 'C'), ('C', 'D'), ('D', 'E')]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Version 2.1.1 requires Python 3.10 or newer and has no third-party dependencies. The license is MIT.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Install the release from PyPI:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install iterquarry
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For a local checkout, install the package in editable mode together with the test extra:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install -e ".[test]"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## What it is for
|
|
58
|
+
|
|
59
|
+
Most of the library yields values lazily. You can pass a generator, a file, or any other iterable, and work starts only when you iterate the result. A few tools need random access or a known length, and those accept a sequence or build a list internally. Each section below says when that happens.
|
|
60
|
+
|
|
61
|
+
Typical uses:
|
|
62
|
+
|
|
63
|
+
- Walk a sequence in pairs, triples, or fixed-width windows.
|
|
64
|
+
- Split a stream into batches, or split it where a predicate changes.
|
|
65
|
+
- Peek at the next item, or step back through items you have already seen.
|
|
66
|
+
- Flatten, interleave, zip, and sort several iterables together.
|
|
67
|
+
- Keep the first item, the last item, or exactly one item, and fail clearly when the count is wrong.
|
|
68
|
+
- Sample, count, group, and reduce without writing the bookkeeping by hand.
|
|
69
|
+
- Generate combinations, permutations, partitions, and prime-related sequences.
|
|
70
|
+
|
|
71
|
+
## Quick start
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from iterquarry import chunked, flatten, windowed
|
|
75
|
+
|
|
76
|
+
list(chunked(range(10), 3))
|
|
77
|
+
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
|
|
78
|
+
|
|
79
|
+
list(windowed(range(1, 6), 3))
|
|
80
|
+
# [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
|
|
81
|
+
|
|
82
|
+
list(flatten([[0, 1], [2, 3]]))
|
|
83
|
+
# [0, 1, 2, 3]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`chunked` collects each batch into a list. `windowed` yields tuples and pads a short final window when you pass `fillvalue`. `flatten` removes one level of nesting.
|
|
87
|
+
|
|
88
|
+
## Grouping and splitting
|
|
89
|
+
|
|
90
|
+
`chunked(iterable, n)` cuts an iterable into lists of length `n`. The last list is shorter when the length does not divide evenly. Pass `strict=True` to raise `ValueError` on a short final batch. `chunked(iterable, None)` returns one list of every item.
|
|
91
|
+
|
|
92
|
+
`chunked_even` keeps the batch sizes as close as possible, with the longer batches first:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from iterquarry import chunked_even
|
|
96
|
+
|
|
97
|
+
list(chunked_even(range(7), 3))
|
|
98
|
+
# [[0, 1, 2], [3, 4], [5, 6]]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`batched` yields tuples and matches the strictness rules of `itertools.batched` on newer Python versions. `grouper` also builds fixed-width tuples. Its `incomplete` argument is `"fill"`, `"ignore"`, or `"strict"`:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from iterquarry import grouper
|
|
105
|
+
|
|
106
|
+
list(grouper("ABCDEFG", 3, incomplete="fill", fillvalue="x"))
|
|
107
|
+
# [('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`distribute` deals items out one by one, the way you deal cards. `divide` cuts the iterable into contiguous blocks. `divide` reads the whole iterable first.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from iterquarry import distribute, divide
|
|
114
|
+
|
|
115
|
+
[list(part) for part in distribute(3, range(8))]
|
|
116
|
+
# [[0, 3, 6], [1, 4, 7], [2, 5]]
|
|
117
|
+
|
|
118
|
+
[list(part) for part in divide(3, range(8))]
|
|
119
|
+
# [[0, 1, 2], [3, 4, 5], [6, 7]]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`split_before`, `split_after`, `split_at`, and `split_when` break an iterable wherever a predicate says so. `split_into` uses an explicit list of sizes.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from iterquarry import split_before
|
|
126
|
+
|
|
127
|
+
[list(group) for group in split_before("abcdef", lambda char: char in "ce")]
|
|
128
|
+
# [['a', 'b'], ['c', 'd'], ['e', 'f']]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`bucket` files each item under a key and lets you read one key at a time:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from iterquarry import bucket
|
|
135
|
+
|
|
136
|
+
grouped = bucket("AbBa", key=str.lower)
|
|
137
|
+
list(grouped["a"])
|
|
138
|
+
# ['A', 'a']
|
|
139
|
+
list(grouped["b"])
|
|
140
|
+
# ['b', 'B']
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`unzip` is the inverse of `zip`: one iterable of tuples becomes one iterator per column.
|
|
144
|
+
|
|
145
|
+
Other grouping tools: `ichunked`, `sliced`, `constrained_batches`, `groupby_transform`, `consecutive_groups`.
|
|
146
|
+
|
|
147
|
+
## Windows
|
|
148
|
+
|
|
149
|
+
`pairwise` yields overlapping pairs. `triplewise` yields overlapping triples. `sliding_window` is the general form and yields a tuple of length `n` on every step.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from iterquarry import sliding_window, triplewise
|
|
153
|
+
|
|
154
|
+
list(triplewise(range(5)))
|
|
155
|
+
# [(0, 1, 2), (1, 2, 3), (2, 3, 4)]
|
|
156
|
+
|
|
157
|
+
list(sliding_window(range(5), 3))
|
|
158
|
+
# [(0, 1, 2), (1, 2, 3), (2, 3, 4)]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`windowed` is the padded variant. Set `step` to move ahead by more than one item, and set `fillvalue` when the tail is shorter than the window. `windowed_complete` yields `(before, window, after)` so you can see the items on both sides of each window.
|
|
162
|
+
|
|
163
|
+
`stagger` zips an iterable with offset copies of itself:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from iterquarry import stagger
|
|
167
|
+
|
|
168
|
+
list(stagger([1, 2, 3, 4, 5], offsets=(-1, 0, 1), longest=True))
|
|
169
|
+
# [(None, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, None), (5, None, None)]
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`substrings` and `subslices` yield every non-empty contiguous slice. `substrings_indexes` yields `(start, end)` pairs for a sequence. `adjacent` marks each item when it, or a neighbor within `distance`, satisfies a predicate.
|
|
173
|
+
|
|
174
|
+
## Lookahead
|
|
175
|
+
|
|
176
|
+
`spy` copies the first few items and returns both that copy and an iterator that still starts at the beginning:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from iterquarry import spy
|
|
180
|
+
|
|
181
|
+
head, remaining = spy("abcdef", 2)
|
|
182
|
+
head
|
|
183
|
+
# ['a', 'b']
|
|
184
|
+
list(remaining)
|
|
185
|
+
# ['a', 'b', 'c', 'd', 'e', 'f']
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`peekable` wraps an iterator so you can inspect the next item without consuming it, and put items back with `prepend`:
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from iterquarry import peekable
|
|
192
|
+
|
|
193
|
+
items = peekable("abc")
|
|
194
|
+
items.peek()
|
|
195
|
+
# 'a'
|
|
196
|
+
next(items)
|
|
197
|
+
# 'a'
|
|
198
|
+
list(items)
|
|
199
|
+
# ['b', 'c']
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Indexing a `peekable` reads ahead as far as the index requires. A negative index reads the rest of the source.
|
|
203
|
+
|
|
204
|
+
`seekable` remembers the items it has produced and can return to an earlier position with `seek`. A `maxlen` limits how far back that cache reaches. `relative_seek` moves from the current position.
|
|
205
|
+
|
|
206
|
+
## Combining iterables
|
|
207
|
+
|
|
208
|
+
`flatten` removes one level of nesting. `collapse` keeps going into nested iterables. Strings and bytes stay intact unless you change `base_type`. `levels` stops the collapse after a fixed depth.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from iterquarry import collapse
|
|
212
|
+
|
|
213
|
+
list(collapse([1, [2, [3, [4]]]]))
|
|
214
|
+
# [1, 2, 3, 4]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`interleave` takes one item from each iterable in turn and stops at the shortest. `interleave_longest` continues until every iterable is exhausted. `roundrobin` does the same with a different internal schedule. `interleave_evenly` spaces shorter iterables through the longest one. `interleave_randomly` picks among the iterables that still have items.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from iterquarry import interleave, roundrobin
|
|
221
|
+
|
|
222
|
+
list(interleave([1, 2, 3], [4, 5], [6]))
|
|
223
|
+
# [1, 4, 6]
|
|
224
|
+
|
|
225
|
+
list(roundrobin("ABC", "D", "EF"))
|
|
226
|
+
# ['A', 'D', 'E', 'B', 'F', 'C']
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`zip_offset` shifts each iterable by a given offset before zipping. `zip_broadcast` repeats strings, bytes, and other scalars across the items of the real iterables. `sort_together` sorts several sequences by one or more columns and returns them in the new order:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from iterquarry import sort_together, zip_offset
|
|
233
|
+
|
|
234
|
+
list(zip_offset("0123", "abcdef", offsets=(0, 1)))
|
|
235
|
+
# [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e')]
|
|
236
|
+
|
|
237
|
+
sort_together([["a", "b", "c"], [3, 1, 2]], key_list=(1,))
|
|
238
|
+
# (('b', 'c', 'a'), (1, 2, 3))
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`prepend` adds one value at the front. `value_chain` yields its arguments, iterating anything that is not a string or bytes. `partial_product` walks a product space one coordinate at a time. `dotproduct` and `transpose` cover the small linear-algebra cases, and `matmul` multiplies two matrices given as iterables of rows.
|
|
242
|
+
|
|
243
|
+
## Selecting items
|
|
244
|
+
|
|
245
|
+
`first` and `last` return one end of an iterable. `take` and `tail` return several items. `nth` returns the item at an index, or a default when the iterable ends first. `nth_or_last` returns the last item when the index runs past the end.
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from iterquarry import first, last, tail, take
|
|
249
|
+
|
|
250
|
+
first([1, 2, 3])
|
|
251
|
+
# 1
|
|
252
|
+
last([1, 2, 3])
|
|
253
|
+
# 3
|
|
254
|
+
take(2, "abcde")
|
|
255
|
+
# ['a', 'b']
|
|
256
|
+
list(tail(2, "abcde"))
|
|
257
|
+
# ['d', 'e']
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`one` requires exactly one item and raises `ValueError` when the iterable is empty or longer. `only` returns the single item, or a default when the iterable is empty, and raises when there is a second item. `strictly_n` yields exactly `n` items and calls `too_short` or `too_long` when the length differs.
|
|
261
|
+
|
|
262
|
+
`unique_everseen` drops items that have already appeared. `unique_justseen` drops only adjacent duplicates. `unique` sorts, then drops duplicates, so it accepts unhashable items. `duplicates_everseen` and `duplicates_justseen` yield the copies that the unique helpers would drop. `unique_in_window` treats an item as new when it has not appeared in the last `n` items.
|
|
263
|
+
|
|
264
|
+
`locate` yields indexes where a predicate is true. `rlocate` yields those indexes from the right. `replace` substitutes matching items, or matching windows when `window_size` is greater than one.
|
|
265
|
+
|
|
266
|
+
`strip`, `lstrip`, and `rstrip` drop leading or trailing items that match a predicate, the way `str.strip` drops characters. `before_and_after` splits once, at the first failing item, and returns both sides:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from iterquarry import before_and_after
|
|
270
|
+
|
|
271
|
+
head, rest = before_and_after(lambda value: value < 3, range(6))
|
|
272
|
+
list(head), list(rest)
|
|
273
|
+
# ([0, 1, 2], [3, 4, 5])
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`partition` splits into the items that fail a predicate and the items that pass. `filter_except` and `map_except` skip items that raise one of the given exceptions. `iter_suppress` does the same while iterating. `filter_map` keeps values that are true after a function runs. `extract` pulls items at selected indexes. `takewhile_inclusive` keeps the first item that fails the predicate, then stops. `longest_common_prefix` walks several iterables until they disagree.
|
|
277
|
+
|
|
278
|
+
## Summaries
|
|
279
|
+
|
|
280
|
+
These helpers reduce an iterable to a count, a flag, or a small aggregate.
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from iterquarry import all_equal, ilen, quantify
|
|
284
|
+
|
|
285
|
+
ilen(range(5))
|
|
286
|
+
# 5
|
|
287
|
+
quantify([1, 0, 2, 0, 3])
|
|
288
|
+
# 3
|
|
289
|
+
all_equal([2, 2, 2])
|
|
290
|
+
# True
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
`all_unique` reports whether every item is distinct. `is_sorted` checks order, with `strict=True` when equal neighbors should fail. `exactly_n` is true when exactly `n` items satisfy a predicate. `iequals` compares several iterables item by item. `minmax` returns the smallest and largest value in one pass. `argmin` and `argmax` return the index of the extreme value.
|
|
294
|
+
|
|
295
|
+
`sample` draws `k` items. It supports `weights`, `counts`, and `strict`. The draw uses the `random` module, so successive calls differ. `run_length.encode` compresses adjacent repeats, and `run_length.decode` expands them:
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
from iterquarry import run_length
|
|
299
|
+
|
|
300
|
+
list(run_length.encode("aaabbca"))
|
|
301
|
+
# [('a', 3), ('b', 2), ('c', 1), ('a', 1)]
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`consecutive_groups` groups values that increase by one. `map_reduce` groups by a key, maps each item, and optionally reduces each group. `join_mappings` merges dictionaries that share keys. `unique_to_each` lists the items that appear in only one of several iterables.
|
|
305
|
+
|
|
306
|
+
## Adding information to a stream
|
|
307
|
+
|
|
308
|
+
`mark_ends` tags the first and last items:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
from iterquarry import mark_ends
|
|
312
|
+
|
|
313
|
+
list(mark_ends("ABC"))
|
|
314
|
+
# [(True, False, 'A'), (False, False, 'B'), (False, True, 'C')]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`count_cycle` pairs each item with a cycle counter. `intersperse` inserts a separator every `n` items. `padded` extends an iterable out to a length, or out to the next multiple of a length. `repeat_each` repeats every item. `repeat_last` yields the final item forever after the source ends. `ncycles` repeats the whole iterable `n` times. `pad_none` is an endless tail of `None`.
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from iterquarry import intersperse, padded, repeat_each
|
|
321
|
+
|
|
322
|
+
list(intersperse("|", "abc"))
|
|
323
|
+
# ['a', '|', 'b', '|', 'c']
|
|
324
|
+
list(padded([1, 2], n=4, fillvalue=0))
|
|
325
|
+
# [1, 2, 0, 0]
|
|
326
|
+
list(repeat_each("AB", 2))
|
|
327
|
+
# ['A', 'A', 'B', 'B']
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
`classify_unique` yields `(item, unique_just_seen, unique_ever_seen)` so a single pass can answer both duplicate questions.
|
|
331
|
+
|
|
332
|
+
## Combinatorics
|
|
333
|
+
|
|
334
|
+
`powerset` yields every subset, shortest first. `distinct_permutations` and `distinct_combinations` skip results that look the same because of repeated values. `circular_shifts` rotates a sequence. `partitions` splits a sequence into contiguous blocks. `set_partitions` splits it into unordered groups.
|
|
335
|
+
|
|
336
|
+
```python
|
|
337
|
+
from iterquarry import circular_shifts, distinct_permutations, powerset, set_partitions
|
|
338
|
+
|
|
339
|
+
list(powerset("AB"))
|
|
340
|
+
# [(), ('A',), ('B',), ('A', 'B')]
|
|
341
|
+
|
|
342
|
+
list(distinct_permutations("AAB"))
|
|
343
|
+
# [('A', 'A', 'B'), ('A', 'B', 'A'), ('B', 'A', 'A')]
|
|
344
|
+
|
|
345
|
+
list(circular_shifts("ABCD"))
|
|
346
|
+
# [('A', 'B', 'C', 'D'), ('B', 'C', 'D', 'A'), ('C', 'D', 'A', 'B'), ('D', 'A', 'B', 'C')]
|
|
347
|
+
|
|
348
|
+
list(set_partitions("abc", 2))
|
|
349
|
+
# [[['a'], ['b', 'c']], [['a', 'b'], ['c']], [['b'], ['a', 'c']]]
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
`gray_product` walks a product so that only one coordinate changes at each step. `derangements` yields permutations with no item left in its original place. `outer_product` applies a function to every pair from two iterables. `powerset_of_sets` builds the power set with set objects.
|
|
353
|
+
|
|
354
|
+
When you need one result by index, use `nth_combination`, `nth_combination_with_replacement`, `nth_permutation`, or `nth_product`. The matching `combination_index`, `combination_with_replacement_index`, `permutation_index`, and `product_index` functions go the other way. `random_product`, `random_permutation`, `random_combination`, `random_combination_with_replacement`, and `random_derangement` each return one result.
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from iterquarry import gray_product, nth_combination
|
|
358
|
+
|
|
359
|
+
list(gray_product("AB", "CD"))
|
|
360
|
+
# [('A', 'C'), ('B', 'C'), ('B', 'D'), ('A', 'D')]
|
|
361
|
+
|
|
362
|
+
nth_combination(range(5), 3, 5)
|
|
363
|
+
# (0, 3, 4)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Numeric helpers
|
|
367
|
+
|
|
368
|
+
`numeric_range` follows the same start, stop, and step pattern as `range`, for any numeric type that supports addition and comparison. That includes `Decimal`, `Fraction`, and `datetime` values. A datetime range needs an explicit `timedelta` step.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
import datetime
|
|
372
|
+
from decimal import Decimal
|
|
373
|
+
from iterquarry import numeric_range
|
|
374
|
+
|
|
375
|
+
list(numeric_range(Decimal("1.0"), Decimal("2.0"), Decimal("0.3")))
|
|
376
|
+
# [Decimal('1.0'), Decimal('1.3'), Decimal('1.6'), Decimal('1.9')]
|
|
377
|
+
|
|
378
|
+
start = datetime.date(2026, 1, 1)
|
|
379
|
+
step = datetime.timedelta(days=1)
|
|
380
|
+
list(numeric_range(start, start + datetime.timedelta(days=3), step))
|
|
381
|
+
# [datetime.date(2026, 1, 1), datetime.date(2026, 1, 2), datetime.date(2026, 1, 3)]
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
`running_min`, `running_max`, `running_mean`, and `running_median` yield the statistic of the items seen so far. Pass `maxlen` to keep a sliding window. `running_statistics` yields a frozen `Stats` value with `size`, `minimum`, `median`, `maximum`, and `mean`.
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from iterquarry import running_mean
|
|
388
|
+
|
|
389
|
+
list(running_mean([1, 2, 3, 4]))
|
|
390
|
+
# [1.0, 1.5, 2.0, 2.5]
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
`difference` yields the first value, then the gap from each item to the one before it. Pass `func` to use a function other than subtraction, or `initial` to set the starting previous value.
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
from iterquarry import difference
|
|
397
|
+
|
|
398
|
+
list(difference([10, 20, 30, 45]))
|
|
399
|
+
# [10, 10, 10, 15]
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`is_prime`, `factor`, `sieve`, `nth_prime`, and `totient` cover common integer-number tasks. `nth_prime` is zero-based, so `nth_prime(0)` is 2 and `nth_prime(10)` is 31. `multinomial` computes a multinomial coefficient. `convolve` combines a signal with a kernel. `dft` and `idft` are the discrete Fourier transform and its inverse.
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
from iterquarry import convolve, factor, is_prime, sieve, totient
|
|
406
|
+
|
|
407
|
+
is_prime(97)
|
|
408
|
+
# True
|
|
409
|
+
list(factor(84))
|
|
410
|
+
# [2, 2, 3, 7]
|
|
411
|
+
list(sieve(20))
|
|
412
|
+
# [2, 3, 5, 7, 11, 13, 17, 19]
|
|
413
|
+
totient(10)
|
|
414
|
+
# 4
|
|
415
|
+
list(convolve([1, -1, -20], [1, -3]))
|
|
416
|
+
# [1, -4, -17, 60]
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
`sum_of_squares`, `polynomial_from_roots`, `polynomial_derivative`, and `polynomial_eval` are small polynomial helpers. `reshape` rearranges a nested iterable into a new shape.
|
|
420
|
+
|
|
421
|
+
## Wrappers
|
|
422
|
+
|
|
423
|
+
`always_iterable` returns an iterator for any object. Strings and bytes are treated as single values. `None` becomes an empty iterator.
|
|
424
|
+
|
|
425
|
+
```python
|
|
426
|
+
from iterquarry import always_iterable
|
|
427
|
+
|
|
428
|
+
list(always_iterable("hi"))
|
|
429
|
+
# ['hi']
|
|
430
|
+
list(always_iterable(None))
|
|
431
|
+
# []
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
`always_reversible` caches a one-shot iterable so it can be reversed. `countable` counts the items that have been consumed in `items_seen`. `sized_iterator` reports a length that shrinks as you iterate. `consumer` primes a generator that receives values with `send`. `with_iter` iterates a context manager and closes it when iteration finishes. `callback_iter` runs a callback in a background thread and exposes the calls through an iterator. `AbortThread` is the exception used to stop that worker. `SequenceView` is a read-only view of a sequence.
|
|
435
|
+
|
|
436
|
+
## Other tools
|
|
437
|
+
|
|
438
|
+
`side_effect` calls a function for each item, or for each chunk, and still yields the original items. Optional `before` and `after` hooks run around the iteration. `iterate` yields `start`, `func(start)`, `func(func(start))`, and so on. `time_limited` stops a slow iterable after a number of seconds and records whether it timed out. `make_decorator` turns an iterable tool into a decorator. `map_if` applies one function when a predicate is true and another when it is false. `doublestarmap` calls a function with each mapping unpacked as keyword arguments. `raise_` raises an exception from a point in an iterator pipeline where a `raise` statement is awkward. `consume` advances an iterator and discards the items. `tabulate`, `repeatfunc`, `iter_except`, `iter_index`, and `loops` cover function tables, repeated calls, and exception-driven iteration.
|
|
439
|
+
|
|
440
|
+
`seekable` and `peekable` are the right tools when a pipeline needs to look backward or forward. `concurrent_tee` copies an iterable out to several threads. `serialize` and `synchronized` take a lock around iteration or around a function.
|
|
441
|
+
|
|
442
|
+
## API reference
|
|
443
|
+
|
|
444
|
+
| Area | Names |
|
|
445
|
+
| --- | --- |
|
|
446
|
+
| Grouping | `chunked`, `chunked_even`, `batched`, `ichunked`, `sliced`, `constrained_batches`, `distribute`, `divide`, `split_at`, `split_before`, `split_after`, `split_into`, `split_when`, `bucket`, `unzip`, `grouper`, `groupby_transform` |
|
|
447
|
+
| Windows | `pairwise`, `windowed`, `sliding_window`, `triplewise`, `stagger`, `windowed_complete`, `substrings`, `substrings_indexes`, `subslices`, `adjacent` |
|
|
448
|
+
| Lookahead | `spy`, `peekable`, `seekable` |
|
|
449
|
+
| Combining | `flatten`, `collapse`, `interleave`, `interleave_longest`, `interleave_evenly`, `interleave_randomly`, `roundrobin`, `zip_offset`, `zip_broadcast`, `sort_together`, `prepend`, `partial_product`, `value_chain`, `dotproduct`, `transpose`, `matmul` |
|
|
450
|
+
| Selecting | `first`, `last`, `one`, `only`, `nth`, `nth_or_last`, `take`, `tail`, `strip`, `lstrip`, `rstrip`, `unique_everseen`, `unique_justseen`, `unique`, `duplicates_everseen`, `duplicates_justseen`, `unique_in_window`, `locate`, `rlocate`, `replace`, `filter_except`, `map_except`, `filter_map`, `iter_suppress`, `before_and_after`, `takewhile_inclusive`, `strictly_n`, `partition`, `extract`, `longest_common_prefix`, `classify_unique` |
|
|
451
|
+
| Summaries | `ilen`, `sample`, `consecutive_groups`, `run_length`, `map_reduce`, `join_mappings`, `all_equal`, `all_unique`, `quantify`, `minmax`, `argmin`, `argmax`, `is_sorted`, `exactly_n`, `iequals`, `unique_to_each`, `first_true` |
|
|
452
|
+
| Augmenting | `count_cycle`, `intersperse`, `padded`, `pad_none`, `padnone`, `mark_ends`, `repeat_each`, `repeat_last`, `ncycles` |
|
|
453
|
+
| Combinatorics | `powerset`, `powerset_of_sets`, `distinct_permutations`, `distinct_combinations`, `partitions`, `set_partitions`, `circular_shifts`, `derangements`, `gray_product`, `outer_product`, `nth_combination`, `nth_combination_with_replacement`, `nth_permutation`, `nth_product`, `combination_index`, `combination_with_replacement_index`, `permutation_index`, `product_index`, `random_product`, `random_permutation`, `random_combination`, `random_combination_with_replacement`, `random_derangement` |
|
|
454
|
+
| Numbers | `numeric_range`, `difference`, `running_min`, `running_max`, `running_mean`, `running_median`, `running_statistics`, `Stats`, `is_prime`, `factor`, `sieve`, `nth_prime`, `totient`, `multinomial`, `convolve`, `dft`, `idft`, `sum_of_squares`, `polynomial_from_roots`, `polynomial_derivative`, `polynomial_eval`, `reshape` |
|
|
455
|
+
| Wrapping | `always_iterable`, `always_reversible`, `countable`, `sized_iterator`, `consumer`, `with_iter`, `callback_iter`, `AbortThread`, `SequenceView` |
|
|
456
|
+
| Other | `side_effect`, `iterate`, `time_limited`, `make_decorator`, `map_if`, `doublestarmap`, `raise_`, `consume`, `tabulate`, `repeatfunc`, `iter_except`, `iter_index`, `loops`, `concurrent_tee`, `serialize`, `synchronized` |
|
|
457
|
+
|
|
458
|
+
Every name in that table is exported from the top-level package:
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
import iterquarry
|
|
462
|
+
|
|
463
|
+
iterquarry.__version__
|
|
464
|
+
# '2.1.1'
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Development
|
|
468
|
+
|
|
469
|
+
Clone the repository, then install it in editable mode and run the test suite:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
pip install -e ".[test]"
|
|
473
|
+
pytest
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Build source and wheel archives with:
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
python -m build
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
The archives are written to `dist/`.
|