pythonic-fp.iterables 5.1.3__py3-none-any.whl → 5.1.4__py3-none-any.whl
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.
- pythonic_fp/iterables/__init__.py +6 -15
- pythonic_fp/iterables/drop_take.py +81 -48
- pythonic_fp/iterables/folding.py +100 -77
- pythonic_fp/iterables/merging.py +61 -47
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/METADATA +11 -10
- pythonic_fp_iterables-5.1.4.dist-info/RECORD +13 -0
- pythonic_fp_iterables-5.1.3.dist-info/RECORD +0 -13
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/WHEEL +0 -0
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -13,20 +13,11 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
-------------------
|
|
16
|
+
.. admonition:: Composing and iterating iterables
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| Module | Description |
|
|
23
|
-
+===========+===========================================+
|
|
24
|
-
| merging | Concatenating and merging iterables |
|
|
25
|
-
+-----------+-------------------------------------------+
|
|
26
|
-
| drop_take | Dropping and taking values from iterables |
|
|
27
|
-
+-----------+-------------------------------------------+
|
|
28
|
-
| folding | Reducing and accumulating iterables |
|
|
29
|
-
+-----------+-------------------------------------------+
|
|
18
|
+
- module **merging:** Concatenating and merging iterables.
|
|
19
|
+
- module **drop_take:** Dropping and taking values from iterables.
|
|
20
|
+
- module **folding:** Reducing and accumulating iterables.
|
|
30
21
|
|
|
31
22
|
.. important::
|
|
32
23
|
|
|
@@ -35,8 +26,8 @@ Tools for iterables
|
|
|
35
26
|
- iterables are not necessarily iterators
|
|
36
27
|
- at all times iterator protocol is assumed to be followed
|
|
37
28
|
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
- all iterators are assumed to be iterable
|
|
30
|
+
- for all iterators ``foobar`` we assume ``iter(foobar) is foobar``
|
|
40
31
|
|
|
41
32
|
"""
|
|
42
33
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
1
|
+
# Copyright 2023-2026 Geoffrey R. Scheller
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -13,12 +13,23 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
Drop and Take
|
|
17
|
-
-------------
|
|
16
|
+
.. admonition:: Drop and Take
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
Functions which drop or take items from an iterable.
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
.. important::
|
|
21
|
+
|
|
22
|
+
If iterable is a multiply referenced iterator, items
|
|
23
|
+
dropped or taken need not be the next consecutive items.
|
|
24
|
+
|
|
25
|
+
.. important::
|
|
26
|
+
|
|
27
|
+
If iterable is mutable, iterator may be affected by the
|
|
28
|
+
current state of the original iterable.
|
|
29
|
+
|
|
30
|
+
.. tip::
|
|
31
|
+
|
|
32
|
+
Prefer immutable iterables over mutable ones.
|
|
22
33
|
|
|
23
34
|
"""
|
|
24
35
|
|
|
@@ -37,11 +48,14 @@ __all__ = [
|
|
|
37
48
|
|
|
38
49
|
|
|
39
50
|
def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
40
|
-
"""
|
|
51
|
+
"""
|
|
52
|
+
.. admonition:: drop
|
|
53
|
+
|
|
54
|
+
Drop the next n items from iterable.
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
:param iterable: Iterable whose items are to be dropped.
|
|
57
|
+
:param n: Number of items to be dropped.
|
|
58
|
+
:yields: The remaining items.
|
|
45
59
|
|
|
46
60
|
"""
|
|
47
61
|
iterator = iter(iterable)
|
|
@@ -54,19 +68,22 @@ def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
|
54
68
|
|
|
55
69
|
|
|
56
70
|
def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
|
|
57
|
-
"""
|
|
71
|
+
"""
|
|
72
|
+
.. admonition:: drop while
|
|
73
|
+
|
|
74
|
+
Drop initial items from iterable while predicate is true.
|
|
58
75
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
:param iterable: Iterable whose items are to be dropped.
|
|
77
|
+
:param pred: Single argument Boolean items function, the "predicate".
|
|
78
|
+
:yields: items starting when ``pred`` returns ``False``.
|
|
62
79
|
|
|
63
80
|
"""
|
|
64
81
|
iterator = iter(iterable)
|
|
65
82
|
while True:
|
|
66
83
|
try:
|
|
67
|
-
|
|
68
|
-
if not pred(
|
|
69
|
-
iterator = concat((
|
|
84
|
+
item = next(iterator)
|
|
85
|
+
if not pred(item):
|
|
86
|
+
iterator = concat((item,), iterator)
|
|
70
87
|
break
|
|
71
88
|
except StopIteration:
|
|
72
89
|
break
|
|
@@ -74,40 +91,46 @@ def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[
|
|
|
74
91
|
|
|
75
92
|
|
|
76
93
|
def take[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
77
|
-
"""
|
|
94
|
+
"""
|
|
95
|
+
.. admonition:: take
|
|
96
|
+
|
|
97
|
+
Return an iterator yielding up to n items from an iterable.
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
:param Iterable: Iterable providing the items to be taken.
|
|
100
|
+
:param n: Number of items to be taken.
|
|
101
|
+
:yields: Up to n items from iterable.
|
|
82
102
|
|
|
83
103
|
"""
|
|
84
104
|
iterator = iter(iterable)
|
|
85
105
|
for _ in range(n):
|
|
86
106
|
try:
|
|
87
|
-
|
|
88
|
-
yield
|
|
107
|
+
item = next(iterator)
|
|
108
|
+
yield item
|
|
89
109
|
except StopIteration:
|
|
90
110
|
break
|
|
91
111
|
|
|
92
112
|
|
|
93
113
|
def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
|
|
94
|
-
"""
|
|
114
|
+
"""
|
|
115
|
+
.. admonition:: take while
|
|
116
|
+
|
|
117
|
+
Return an iterator of items until predicate false.
|
|
95
118
|
|
|
96
|
-
|
|
119
|
+
:param iterable: Iterable providing the items to be taken.
|
|
120
|
+
:param pred: Single argument Boolean valued function, the "predicate".
|
|
121
|
+
:yields: Items from iterable while predicate is true.
|
|
97
122
|
|
|
98
|
-
|
|
123
|
+
.. warning::
|
|
99
124
|
|
|
100
|
-
|
|
101
|
-
:param pred: Single argument Boolean valued function, the "predicate".
|
|
102
|
-
:returns: An Iterator of of values from iterable until predicate false.
|
|
125
|
+
Risk of data loss if iterable is multiple referenced iterator.
|
|
103
126
|
|
|
104
127
|
"""
|
|
105
128
|
iterator = iter(iterable)
|
|
106
129
|
while True:
|
|
107
130
|
try:
|
|
108
|
-
|
|
109
|
-
if pred(
|
|
110
|
-
yield
|
|
131
|
+
item = next(iterator)
|
|
132
|
+
if pred(item):
|
|
133
|
+
yield item
|
|
111
134
|
else:
|
|
112
135
|
break
|
|
113
136
|
except StopIteration:
|
|
@@ -115,16 +138,21 @@ def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[
|
|
|
115
138
|
|
|
116
139
|
|
|
117
140
|
def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[D]]:
|
|
118
|
-
"""
|
|
141
|
+
"""
|
|
142
|
+
.. admonition:: take split
|
|
143
|
+
|
|
144
|
+
Same as take except also return an iterator of
|
|
145
|
+
the remaining items.
|
|
119
146
|
|
|
120
|
-
|
|
147
|
+
.. admonition:: CONTRACT
|
|
121
148
|
|
|
122
|
-
|
|
123
|
-
|
|
149
|
+
**CONTRACT:** Do not access the second iterator until
|
|
150
|
+
the first one is completely exhausted.
|
|
124
151
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
152
|
+
:param iterable: Iterable providing the items to be taken.
|
|
153
|
+
:param n: maximum Number of items to be taken.
|
|
154
|
+
:returns: A tuple containing an iterator of items taken
|
|
155
|
+
and an iterator of remaining items.
|
|
128
156
|
|
|
129
157
|
"""
|
|
130
158
|
iterator = iter(iterable)
|
|
@@ -136,16 +164,21 @@ def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[
|
|
|
136
164
|
def take_while_split[D](
|
|
137
165
|
iterable: Iterable[D], pred: Callable[[D], bool]
|
|
138
166
|
) -> tuple[Iterator[D], Iterator[D]]:
|
|
139
|
-
"""
|
|
167
|
+
"""
|
|
168
|
+
.. admonition:: take while
|
|
169
|
+
|
|
170
|
+
Same as take_while except also return an iterator of
|
|
171
|
+
the remaining items.
|
|
140
172
|
|
|
141
|
-
|
|
173
|
+
.. admonition:: CONTRACT
|
|
142
174
|
|
|
143
|
-
|
|
144
|
-
|
|
175
|
+
**CONTRACT:** Do not access the second iterator until
|
|
176
|
+
the first one is completely exhausted.
|
|
145
177
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
178
|
+
:param iterable: Iterable providing the items to be taken.
|
|
179
|
+
:param pred: Single argument Boolean valued function.
|
|
180
|
+
:returns: A tuple containing an iterator of items taken while
|
|
181
|
+
``pred`` truthy and an iterator of remaining items.
|
|
149
182
|
|
|
150
183
|
"""
|
|
151
184
|
|
|
@@ -163,7 +196,7 @@ def take_while_split[D](
|
|
|
163
196
|
break
|
|
164
197
|
|
|
165
198
|
iterator = iter(iterable)
|
|
166
|
-
|
|
167
|
-
it_pred = _take_while(iterator, pred,
|
|
199
|
+
item: Box[D] = Box()
|
|
200
|
+
it_pred = _take_while(iterator, pred, item)
|
|
168
201
|
|
|
169
|
-
return it_pred, concat(
|
|
202
|
+
return it_pred, concat(item, iterator)
|
pythonic_fp/iterables/folding.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
1
|
+
# Copyright 2023-2026 Geoffrey R. Scheller
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -13,12 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
Folding
|
|
17
|
-
-------
|
|
16
|
+
.. admonition:: Folding and Accumulating
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Functions to reduce and accumulate values from iterables.
|
|
18
|
+
Functions to reduce and accumulate items from iterables.
|
|
22
19
|
|
|
23
20
|
"""
|
|
24
21
|
|
|
@@ -42,17 +39,24 @@ __all__ = [
|
|
|
42
39
|
def accumulate[D, L](
|
|
43
40
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
|
|
44
41
|
) -> Iterator[L]:
|
|
45
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
.. admonition:: accumulate
|
|
44
|
+
|
|
45
|
+
Returns an iterator of partial fold items. A pure Python
|
|
46
|
+
version of
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
:param iterable: Iterable to be folded.
|
|
49
|
+
:param f: Two parameter function, first parameter for accumulated items.
|
|
50
|
+
:param initial: Optional ``initial`` item to start fold.
|
|
51
|
+
:yields: The intermediate folded items.
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
- begins accumulation with an "optional" ``initial`` value
|
|
53
|
+
.. note::
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
A pure Python implementation of the standard
|
|
56
|
+
library's ``itertools.accumulate``
|
|
57
|
+
|
|
58
|
+
- function ``f`` does not default to addition (for typing flexibility)
|
|
59
|
+
- begins accumulation with an optional ``initial`` item
|
|
56
60
|
|
|
57
61
|
"""
|
|
58
62
|
it = iter(iterable)
|
|
@@ -80,21 +84,21 @@ def accumulate[D, L](
|
|
|
80
84
|
|
|
81
85
|
|
|
82
86
|
def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
.. Warning::
|
|
87
|
+
"""
|
|
88
|
+
.. admonition:: reduce left
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
Fold an iterable left with a function.
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
:param iterable: Iterable to be reduced (folded).
|
|
93
|
+
:param f: Two parameter function, first parameter for accumulated items.
|
|
94
|
+
:return: Reduced item from the iterable.
|
|
95
|
+
:raises StopIteration: When called on an empty iterable.
|
|
96
|
+
:raises Exception: Does not catch any exceptions from ``f``.
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
.. warning::
|
|
92
99
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
:return: reduced value from the iterable
|
|
96
|
-
:raises StopIteration: when called on an empty iterable
|
|
97
|
-
:raises Exception: does not catch any exceptions from ``f``
|
|
100
|
+
- never returns if given an infinite iterable
|
|
101
|
+
- does not catch or re-raises exceptions raised by ``f``
|
|
98
102
|
|
|
99
103
|
"""
|
|
100
104
|
it = iter(iterable)
|
|
@@ -113,24 +117,24 @@ def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
|
|
|
113
117
|
def fold_left[D, L](
|
|
114
118
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L
|
|
115
119
|
) -> L | Never:
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
- not restricted to ``__add__`` for the folding function
|
|
119
|
-
- initial value required, does not default to ``0`` for initial value
|
|
120
|
-
- handles non-numeric data just find
|
|
120
|
+
"""
|
|
121
|
+
.. admonition:: fold left
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
Fold an iterable left with a function and initial item.
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
- not restricted to ``__add__`` for the folding function
|
|
126
|
+
- initial item is required, does not default to ``0``
|
|
127
|
+
- handles non-numeric data just find
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
:param iterable: iterable to be folded
|
|
130
|
+
:param f: two parameter function, first parameter for accumulated item
|
|
131
|
+
:param initial: mandatory initial item to start fold
|
|
132
|
+
:return: the folded item
|
|
127
133
|
|
|
128
|
-
|
|
134
|
+
.. warning::
|
|
129
135
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
:param initial: mandatory initial value to start fold
|
|
133
|
-
:return: the folded value
|
|
136
|
+
- never returns if given an infinite iterable
|
|
137
|
+
- does not catch or re-raises exceptions raised by ``f``
|
|
134
138
|
|
|
135
139
|
"""
|
|
136
140
|
acc = initial
|
|
@@ -142,24 +146,24 @@ def fold_left[D, L](
|
|
|
142
146
|
def maybe_fold_left[D, L](
|
|
143
147
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
|
|
144
148
|
) -> MayBe[L] | Never:
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
- when an initial value is not given then ``L = D``
|
|
148
|
-
- if iterable empty and no ``initial`` value given, return ``MayBe()``
|
|
149
|
+
"""
|
|
150
|
+
.. admonition:: maybe fold left
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
Folds an iterable left with an "optional" initial item.
|
|
151
153
|
|
|
152
|
-
|
|
154
|
+
- when an initial item is not given then ``L = D``
|
|
155
|
+
- if iterable empty and no ``initial`` item given, return ``MayBe()``
|
|
153
156
|
|
|
154
|
-
|
|
157
|
+
:param iterable: The iterable to be folded.
|
|
158
|
+
:param f: First argument is for the accumulated items.
|
|
159
|
+
:param initial: Mandatory initial item to start fold.
|
|
160
|
+
:return: ``MayBe`` of a successfully folded item,
|
|
161
|
+
otherwise returns ``MayBe()``.
|
|
155
162
|
|
|
156
|
-
|
|
157
|
-
exception what-so-ever. The exception is thrown away.
|
|
163
|
+
.. warning::
|
|
158
164
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
:param initial: Mandatory initial value to start fold.
|
|
162
|
-
:return: MayBe of a successfully folded value, otherwise MayBe()
|
|
165
|
+
- never returns if given an infinite iterable
|
|
166
|
+
- any exception ``f`` raises is thrown away
|
|
163
167
|
|
|
164
168
|
"""
|
|
165
169
|
acc: L
|
|
@@ -189,23 +193,33 @@ def sc_reduce_left[D](
|
|
|
189
193
|
include_start: bool = True,
|
|
190
194
|
include_stop: bool = True,
|
|
191
195
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
192
|
-
"""
|
|
196
|
+
"""
|
|
197
|
+
.. admonition:: short circuit reduce left
|
|
198
|
+
|
|
199
|
+
Short circuit version of a left fold.
|
|
200
|
+
|
|
201
|
+
:param iterable: Iterable to be reduced from the left.
|
|
202
|
+
:param f: Two parameter function, first parameter for
|
|
203
|
+
the accumulator.
|
|
204
|
+
:param start: Delay starting the fold until it returns true.
|
|
205
|
+
:param stop: Prematurely stop the fold when it returns true.
|
|
206
|
+
:param include_start: If true, include starting item in fold.
|
|
207
|
+
:param include_stop: If true, include stopping item in fold.
|
|
208
|
+
:return: Tuple of a ``MayBe`` of the folded item and iterator
|
|
209
|
+
of remaining iterables.
|
|
210
|
+
|
|
211
|
+
.. note::
|
|
193
212
|
|
|
194
|
-
|
|
213
|
+
Behavior for default arguments will
|
|
195
214
|
|
|
196
|
-
|
|
215
|
+
- left reduce finite iterable
|
|
216
|
+
- start folding immediately
|
|
217
|
+
- continue folding until end (of a possibly infinite iterable)
|
|
197
218
|
|
|
198
|
-
|
|
199
|
-
- start folding immediately
|
|
200
|
-
- continue folding until end (of a possibly infinite iterable)
|
|
219
|
+
.. tip::
|
|
201
220
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
:param start: delay starting the fold until it returns true
|
|
205
|
-
:param stop: prematurely stop the fold when it returns true
|
|
206
|
-
:param include_start: if true, include fold starting value in fold
|
|
207
|
-
:param include_stop: if true, include stopping value in fold
|
|
208
|
-
:return: tuple of a MayBe of the folded value and iterator of remaining iterables
|
|
221
|
+
Useful for infinite iterables when Callable ``stop``
|
|
222
|
+
is provided.
|
|
209
223
|
|
|
210
224
|
"""
|
|
211
225
|
it_start = drop_while(iterable, negate(start))
|
|
@@ -241,23 +255,32 @@ def sc_reduce_right[D](
|
|
|
241
255
|
include_start: bool = True,
|
|
242
256
|
include_stop: bool = True,
|
|
243
257
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
244
|
-
"""
|
|
258
|
+
"""
|
|
259
|
+
.. admonition:: short circuit reduce right
|
|
260
|
+
|
|
261
|
+
Short circuit version of a right fold.
|
|
262
|
+
|
|
263
|
+
:param iterable: Iterable to be reduced from the right.
|
|
264
|
+
:param f: Two parameter function, second parameter for
|
|
265
|
+
the accumulator.
|
|
266
|
+
:param start: Delay starting the fold until it returns true.
|
|
267
|
+
:param stop: Prematurely stop the fold when it returns true.
|
|
268
|
+
:param include_start: If true, include starting item.
|
|
269
|
+
:param include_stop: If true, include stopping item in fold.
|
|
270
|
+
:return: Tuple of a ``MayBe`` of the folded item and iterator
|
|
271
|
+
of remaining iterables.
|
|
272
|
+
|
|
273
|
+
.. note::
|
|
245
274
|
|
|
246
|
-
|
|
275
|
+
Behavior for default arguments will
|
|
247
276
|
|
|
248
|
-
|
|
277
|
+
- right reduce finite iterable
|
|
278
|
+
- start folding at end (of a possibly infinite iterable)
|
|
279
|
+
- continue reducing right until beginning
|
|
249
280
|
|
|
250
|
-
|
|
251
|
-
- start folding at end (of a possibly infinite iterable)
|
|
252
|
-
- continue reducing right until beginning
|
|
281
|
+
.. tip::
|
|
253
282
|
|
|
254
|
-
|
|
255
|
-
:param f: two parameter function, second parameter for accumulated value
|
|
256
|
-
:param start: delay starting the fold until it returns true
|
|
257
|
-
:param stop: prematurely stop the fold when it returns true
|
|
258
|
-
:param include_start: if true, include fold starting value in fold
|
|
259
|
-
:param include_stop: if true, include stopping value in fold
|
|
260
|
-
:return: tuple of a MayBe of the folded value and iterator of remaining iterables
|
|
283
|
+
Useful for infinite and non-reversible iterables.
|
|
261
284
|
|
|
262
285
|
"""
|
|
263
286
|
it_start, it_rest = take_while_split(iterable, negate(start))
|
pythonic_fp/iterables/merging.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
1
|
+
# Copyright 2023-2026 Geoffrey R. Scheller
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -13,10 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
Merging
|
|
17
|
-
-----------------
|
|
18
|
-
|
|
19
|
-
.. admonition:: module pythonic_fp.iterables.merging
|
|
16
|
+
.. admonition:: Merging iterables
|
|
20
17
|
|
|
21
18
|
Functions to merge multiple iterables together into one.
|
|
22
19
|
|
|
@@ -35,98 +32,112 @@ __all__ = [
|
|
|
35
32
|
|
|
36
33
|
|
|
37
34
|
class MergeEnum(Enum):
|
|
38
|
-
"""
|
|
35
|
+
"""
|
|
36
|
+
.. admonition:: Iterable Blending Enums.
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
- **MergeEnum.Concat:** Concatenate first to last
|
|
39
|
+
- **MergeEnum.Merge:** Merge until one is exhausted
|
|
40
|
+
- **MergeEnum.Exhaust:** Merge until all are exhausted
|
|
43
41
|
|
|
44
42
|
"""
|
|
45
|
-
|
|
46
43
|
Concat = auto()
|
|
47
44
|
Merge = auto()
|
|
48
45
|
Exhaust = auto()
|
|
49
46
|
|
|
50
47
|
|
|
51
48
|
def concat[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
52
|
-
"""
|
|
49
|
+
"""
|
|
50
|
+
.. admonition:: concatenate iterables
|
|
51
|
+
|
|
52
|
+
Sequentially concatenate multiple iterables.
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
yielding any values.
|
|
54
|
+
:param iterables: Iterables to concatenate.
|
|
55
|
+
:yields: The concatenated items from all the iterables.
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
.. warning::
|
|
58
|
+
An infinite iterable will prevent subsequent iterables from
|
|
59
|
+
yielding any items.
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
.. note::
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
:returns: Iterator of concatenated values from the iterables.
|
|
63
|
+
Performant to the standard library's ``itertools.chain``.
|
|
64
64
|
|
|
65
65
|
"""
|
|
66
66
|
for iterator in map(lambda x: iter(x), iterables):
|
|
67
67
|
while True:
|
|
68
68
|
try:
|
|
69
|
-
|
|
70
|
-
yield
|
|
69
|
+
item = next(iterator)
|
|
70
|
+
yield item
|
|
71
71
|
except StopIteration:
|
|
72
72
|
break
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]:
|
|
76
|
-
"""
|
|
76
|
+
"""
|
|
77
|
+
.. admonition:: merge iterables
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Merge multiple iterables until one is exhausted.
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
:param iterables: Iterables to merge until one gets exhausted.
|
|
82
|
+
:param yield_partials: Yield any unpaired yielded items from other iterables.
|
|
83
|
+
:yields: Merged items from the iterables until one of the
|
|
84
|
+
iterables is exhausted.
|
|
83
85
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
.. note::
|
|
87
|
+
|
|
88
|
+
When ``yield_partials`` is true, then any unmatched items
|
|
89
|
+
from other iterables already yielded when the first iterable
|
|
90
|
+
is exhausted are yielded.
|
|
91
|
+
|
|
92
|
+
This prevents data lose if any of the iterables are
|
|
93
|
+
iterators with external references.
|
|
87
94
|
|
|
88
95
|
"""
|
|
89
96
|
iter_list = list(map(lambda x: iter(x), iterables))
|
|
90
|
-
|
|
97
|
+
items = []
|
|
91
98
|
if (num_iters := len(iter_list)) > 0:
|
|
92
99
|
while True:
|
|
93
100
|
try:
|
|
94
101
|
for ii in range(num_iters):
|
|
95
|
-
|
|
96
|
-
yield from
|
|
97
|
-
|
|
102
|
+
items.append(next(iter_list[ii]))
|
|
103
|
+
yield from items
|
|
104
|
+
items.clear()
|
|
98
105
|
except StopIteration:
|
|
99
106
|
break
|
|
100
107
|
if yield_partials:
|
|
101
|
-
yield from
|
|
108
|
+
yield from items
|
|
102
109
|
|
|
103
110
|
|
|
104
111
|
def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
105
|
-
"""
|
|
112
|
+
"""
|
|
113
|
+
.. admonition:: exhaustively merge iterables
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
Merge multiple iterables until all are exhausted.
|
|
116
|
+
|
|
117
|
+
:param iterables: Iterables to exhaustively merge.
|
|
118
|
+
:yields: Merged items from the iterables until all of the
|
|
119
|
+
iterables are exhausted.
|
|
109
120
|
|
|
110
121
|
"""
|
|
111
122
|
iter_list = list(map(lambda x: iter(x), iterables))
|
|
112
123
|
if (num_iters := len(iter_list)) > 0:
|
|
113
124
|
ii = 0
|
|
114
|
-
|
|
125
|
+
items = []
|
|
115
126
|
while True:
|
|
116
127
|
try:
|
|
117
128
|
while ii < num_iters:
|
|
118
|
-
|
|
129
|
+
items.append(next(iter_list[ii]))
|
|
119
130
|
ii += 1
|
|
120
|
-
yield from
|
|
131
|
+
yield from items
|
|
121
132
|
ii = 0
|
|
122
|
-
|
|
133
|
+
items.clear()
|
|
123
134
|
except StopIteration:
|
|
124
135
|
num_iters -= 1
|
|
125
136
|
if num_iters < 1:
|
|
126
137
|
break
|
|
127
138
|
del iter_list[ii]
|
|
128
139
|
|
|
129
|
-
yield from
|
|
140
|
+
yield from items
|
|
130
141
|
|
|
131
142
|
|
|
132
143
|
def blend[D](
|
|
@@ -134,13 +145,16 @@ def blend[D](
|
|
|
134
145
|
merge_enum: MergeEnum = MergeEnum.Concat,
|
|
135
146
|
yield_partials: bool = False,
|
|
136
147
|
) -> Iterator[D]:
|
|
137
|
-
"""
|
|
148
|
+
"""
|
|
149
|
+
.. admonition:: merge iterables
|
|
150
|
+
|
|
151
|
+
Merge behavior based on value of merge_enum parameter.
|
|
138
152
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
:param iterables: Iterables to blend together.
|
|
154
|
+
:param merge_enum: ``MergeEnum`` to determine merging behavior.
|
|
155
|
+
:param yield_partials: Yield unpaired items from other iterables.
|
|
156
|
+
:yields: Items from all iterables blended together.
|
|
157
|
+
:raises ValueError: When an unknown ``MergeEnum`` is given.
|
|
144
158
|
|
|
145
159
|
"""
|
|
146
160
|
match merge_enum:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-iterables
|
|
3
|
-
Version: 5.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 5.1.4
|
|
4
|
+
Summary: .. admonition:: Composing and iterating iterables
|
|
5
5
|
Keywords: iterables,iterators
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
7
|
Requires-Python: >=3.13
|
|
@@ -11,15 +11,15 @@ Classifier: Framework :: Pytest
|
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
15
|
Classifier: Typing :: Typed
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: pythonic-fp-fptools>=5.2.0
|
|
18
18
|
Requires-Dist: pythonic-fp-gadgets>=4.0.2
|
|
19
19
|
Requires-Dist: pytest>=8.4.1 ; extra == "test"
|
|
20
20
|
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-iterables/blob/main/CHANGELOG.rst
|
|
21
|
-
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/iterables
|
|
22
|
-
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
21
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/projects/iterables.html
|
|
22
|
+
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
23
23
|
Project-URL: Source, https://github.com/grscheller/pythonic-fp-iterables
|
|
24
24
|
Provides-Extra: test
|
|
25
25
|
|
|
@@ -27,7 +27,8 @@ Pythonic FP - Tools for iterables
|
|
|
27
27
|
=================================
|
|
28
28
|
|
|
29
29
|
PyPI project
|
|
30
|
-
`pythonic-fp
|
|
30
|
+
`pythonic-fp-iterators
|
|
31
|
+
<https://pypi.org/project/pythonic-fp-iterables>`_.
|
|
31
32
|
|
|
32
33
|
Library of functions for iterating iterables.
|
|
33
34
|
|
|
@@ -44,19 +45,19 @@ Library of functions for iterating iterables.
|
|
|
44
45
|
|
|
45
46
|
Part of the
|
|
46
47
|
`pythonic-fp
|
|
47
|
-
<https://grscheller.github.io/pythonic-fp
|
|
48
|
+
<https://grscheller.github.io/pythonic-fp/>`_
|
|
48
49
|
PyPI projects.
|
|
49
50
|
|
|
50
51
|
Documentation
|
|
51
52
|
-------------
|
|
52
53
|
|
|
53
|
-
Documentation for this project
|
|
54
|
+
Documentation and other links for this project are hosted on
|
|
54
55
|
`GitHub Pages
|
|
55
|
-
<https://grscheller.github.io/pythonic-fp/iterables>`_.
|
|
56
|
+
<https://grscheller.github.io/pythonic-fp/projects/iterables.html>`_.
|
|
56
57
|
|
|
57
58
|
Copyright and License
|
|
58
59
|
---------------------
|
|
59
60
|
|
|
60
|
-
Copyright (c) 2023-
|
|
61
|
+
Copyright (c) 2023-2026 Geoffrey R. Scheller. Licensed under the Apache
|
|
61
62
|
License, Version 2.0. See the LICENSE file for details.
|
|
62
63
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
pythonic_fp/iterables/__init__.py,sha256=j-Z9XV73LehhLwYvi_Wzhml7hPaEbHiRjRJt-BI6RKs,1255
|
|
2
|
+
pythonic_fp/iterables/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
pythonic_fp/iterables/drop_take.py,sha256=0ydMGx-aj_-aK5PIx7Rowh_9h0niC6bRKMSotHjvy1g,5558
|
|
4
|
+
pythonic_fp/iterables/drop_take.pyi,sha256=vPyByY4PxCGEuL6trI0aTK8fBr4xCuOgqhaKALwJ5Ys,653
|
|
5
|
+
pythonic_fp/iterables/folding.py,sha256=tqFzxzWLpK6qIS9ff8tTwv58q2h4gjBAyuHrNeEWi20,9347
|
|
6
|
+
pythonic_fp/iterables/folding.pyi,sha256=ZVrpB-D4kWoVwpCsQ2rc3GJ8iTzavAOQ5YK9LteAukU,1175
|
|
7
|
+
pythonic_fp/iterables/merging.py,sha256=acQ8_Iw07CVvOnB_D8dbLvmkjv7P48CysareWlfAbRc,4912
|
|
8
|
+
pythonic_fp/iterables/merging.pyi,sha256=KnuSFREXEpnbtTvMWsvn-KfeSjZ3ybP-6n9hCxjNKVs,533
|
|
9
|
+
pythonic_fp/iterables/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
pythonic_fp_iterables-5.1.4.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
11
|
+
pythonic_fp_iterables-5.1.4.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
12
|
+
pythonic_fp_iterables-5.1.4.dist-info/METADATA,sha256=zOdoxJujuqsKpXHZqKfI-0wJRmnKEDdy5T_KjMXMJGQ,2096
|
|
13
|
+
pythonic_fp_iterables-5.1.4.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
pythonic_fp/iterables/__init__.py,sha256=oAoufgaFeHBH81d-ey738bBsVSximbrp0Rseb3EafnI,1663
|
|
2
|
-
pythonic_fp/iterables/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
pythonic_fp/iterables/drop_take.py,sha256=Kvj-B_xXD9t4tsIjMRdMXwSDKAeUsfbtLPs6X7wRapg,4847
|
|
4
|
-
pythonic_fp/iterables/drop_take.pyi,sha256=vPyByY4PxCGEuL6trI0aTK8fBr4xCuOgqhaKALwJ5Ys,653
|
|
5
|
-
pythonic_fp/iterables/folding.py,sha256=5-EJT-lp8EhAghMlNghla3rnVL0ywRS3-kGuO13oEVI,8711
|
|
6
|
-
pythonic_fp/iterables/folding.pyi,sha256=ZVrpB-D4kWoVwpCsQ2rc3GJ8iTzavAOQ5YK9LteAukU,1175
|
|
7
|
-
pythonic_fp/iterables/merging.py,sha256=mJ4nmIxSwuoi8LvYTHbU-JEUqkii1BdociRs59Dxq-A,4613
|
|
8
|
-
pythonic_fp/iterables/merging.pyi,sha256=KnuSFREXEpnbtTvMWsvn-KfeSjZ3ybP-6n9hCxjNKVs,533
|
|
9
|
-
pythonic_fp/iterables/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
pythonic_fp_iterables-5.1.3.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
11
|
-
pythonic_fp_iterables-5.1.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
12
|
-
pythonic_fp_iterables-5.1.3.dist-info/METADATA,sha256=Mi8wDsA-nnmMXWfrhS42W1CULGDYOcsSRqTk1nxNJNo,2064
|
|
13
|
-
pythonic_fp_iterables-5.1.3.dist-info/RECORD,,
|
|
File without changes
|
{pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|