pythonic-fp.iterables 5.1.2__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 +13 -19
- pythonic_fp/iterables/drop_take.py +84 -48
- pythonic_fp/iterables/folding.py +104 -73
- pythonic_fp/iterables/merging.py +66 -44
- {pythonic_fp_iterables-5.1.2.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/METADATA +13 -12
- pythonic_fp_iterables-5.1.4.dist-info/RECORD +13 -0
- pythonic_fp_iterables-5.1.2.dist-info/RECORD +0 -13
- {pythonic_fp_iterables-5.1.2.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/WHEEL +0 -0
- {pythonic_fp_iterables-5.1.2.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -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,30 +13,24 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
============================================
|
|
16
|
+
.. admonition:: Composing and iterating iterables
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| merging | Concatenating and merging iterables |
|
|
23
|
-
+-----------+-------------------------------------------+
|
|
24
|
-
| drop_take | Dropping and taking values from iterables |
|
|
25
|
-
+-----------+-------------------------------------------+
|
|
26
|
-
| folding | Reducing and accumulating iterables |
|
|
27
|
-
+-----------+-------------------------------------------+
|
|
18
|
+
- module **merging:** Concatenating and merging iterables.
|
|
19
|
+
- module **drop_take:** Dropping and taking values from iterables.
|
|
20
|
+
- module **folding:** Reducing and accumulating iterables.
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
-----------
|
|
22
|
+
.. important::
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
- at all times iterator protocol is assumed to be followed
|
|
24
|
+
**Assumptions:**
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
- iterables are not necessarily iterators
|
|
27
|
+
- at all times iterator protocol is assumed to be followed
|
|
28
|
+
|
|
29
|
+
- all iterators are assumed to be iterable
|
|
30
|
+
- for all iterators ``foobar`` we assume ``iter(foobar) is foobar``
|
|
37
31
|
|
|
38
32
|
"""
|
|
39
33
|
|
|
40
34
|
__author__ = 'Geoffrey R. Scheller'
|
|
41
|
-
__copyright__ = 'Copyright (c) 2023-
|
|
35
|
+
__copyright__ = 'Copyright (c) 2023-2026 Geoffrey R. Scheller'
|
|
42
36
|
__license__ = 'Apache License 2.0'
|
|
@@ -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,7 +13,24 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
|
|
16
|
+
.. admonition:: Drop and Take
|
|
17
|
+
|
|
18
|
+
Functions which drop or take items from an iterable.
|
|
19
|
+
|
|
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.
|
|
33
|
+
|
|
17
34
|
"""
|
|
18
35
|
|
|
19
36
|
from collections.abc import Callable, Iterable, Iterator
|
|
@@ -30,15 +47,15 @@ __all__ = [
|
|
|
30
47
|
]
|
|
31
48
|
|
|
32
49
|
|
|
33
|
-
## dropping and taking
|
|
34
|
-
|
|
35
|
-
|
|
36
50
|
def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
37
|
-
"""
|
|
51
|
+
"""
|
|
52
|
+
.. admonition:: drop
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
54
|
+
Drop the next n items from iterable.
|
|
55
|
+
|
|
56
|
+
:param iterable: Iterable whose items are to be dropped.
|
|
57
|
+
:param n: Number of items to be dropped.
|
|
58
|
+
:yields: The remaining items.
|
|
42
59
|
|
|
43
60
|
"""
|
|
44
61
|
iterator = iter(iterable)
|
|
@@ -51,19 +68,22 @@ def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
|
51
68
|
|
|
52
69
|
|
|
53
70
|
def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
|
|
54
|
-
"""
|
|
71
|
+
"""
|
|
72
|
+
.. admonition:: drop while
|
|
73
|
+
|
|
74
|
+
Drop initial items from iterable while predicate is true.
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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``.
|
|
59
79
|
|
|
60
80
|
"""
|
|
61
81
|
iterator = iter(iterable)
|
|
62
82
|
while True:
|
|
63
83
|
try:
|
|
64
|
-
|
|
65
|
-
if not pred(
|
|
66
|
-
iterator = concat((
|
|
84
|
+
item = next(iterator)
|
|
85
|
+
if not pred(item):
|
|
86
|
+
iterator = concat((item,), iterator)
|
|
67
87
|
break
|
|
68
88
|
except StopIteration:
|
|
69
89
|
break
|
|
@@ -71,40 +91,46 @@ def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[
|
|
|
71
91
|
|
|
72
92
|
|
|
73
93
|
def take[D](iterable: Iterable[D], n: int) -> Iterator[D]:
|
|
74
|
-
"""
|
|
94
|
+
"""
|
|
95
|
+
.. admonition:: take
|
|
96
|
+
|
|
97
|
+
Return an iterator yielding up to n items from an iterable.
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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.
|
|
79
102
|
|
|
80
103
|
"""
|
|
81
104
|
iterator = iter(iterable)
|
|
82
105
|
for _ in range(n):
|
|
83
106
|
try:
|
|
84
|
-
|
|
85
|
-
yield
|
|
107
|
+
item = next(iterator)
|
|
108
|
+
yield item
|
|
86
109
|
except StopIteration:
|
|
87
110
|
break
|
|
88
111
|
|
|
89
112
|
|
|
90
113
|
def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
|
|
91
|
-
"""
|
|
114
|
+
"""
|
|
115
|
+
.. admonition:: take while
|
|
92
116
|
|
|
93
|
-
|
|
117
|
+
Return an iterator of items until predicate false.
|
|
94
118
|
|
|
95
|
-
|
|
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.
|
|
96
122
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
.. warning::
|
|
124
|
+
|
|
125
|
+
Risk of data loss if iterable is multiple referenced iterator.
|
|
100
126
|
|
|
101
127
|
"""
|
|
102
128
|
iterator = iter(iterable)
|
|
103
129
|
while True:
|
|
104
130
|
try:
|
|
105
|
-
|
|
106
|
-
if pred(
|
|
107
|
-
yield
|
|
131
|
+
item = next(iterator)
|
|
132
|
+
if pred(item):
|
|
133
|
+
yield item
|
|
108
134
|
else:
|
|
109
135
|
break
|
|
110
136
|
except StopIteration:
|
|
@@ -112,16 +138,21 @@ def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[
|
|
|
112
138
|
|
|
113
139
|
|
|
114
140
|
def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[D]]:
|
|
115
|
-
"""
|
|
141
|
+
"""
|
|
142
|
+
.. admonition:: take split
|
|
143
|
+
|
|
144
|
+
Same as take except also return an iterator of
|
|
145
|
+
the remaining items.
|
|
116
146
|
|
|
117
|
-
|
|
147
|
+
.. admonition:: CONTRACT
|
|
118
148
|
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
**CONTRACT:** Do not access the second iterator until
|
|
150
|
+
the first one is completely exhausted.
|
|
121
151
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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.
|
|
125
156
|
|
|
126
157
|
"""
|
|
127
158
|
iterator = iter(iterable)
|
|
@@ -133,16 +164,21 @@ def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[
|
|
|
133
164
|
def take_while_split[D](
|
|
134
165
|
iterable: Iterable[D], pred: Callable[[D], bool]
|
|
135
166
|
) -> tuple[Iterator[D], Iterator[D]]:
|
|
136
|
-
"""
|
|
167
|
+
"""
|
|
168
|
+
.. admonition:: take while
|
|
169
|
+
|
|
170
|
+
Same as take_while except also return an iterator of
|
|
171
|
+
the remaining items.
|
|
137
172
|
|
|
138
|
-
|
|
173
|
+
.. admonition:: CONTRACT
|
|
139
174
|
|
|
140
|
-
|
|
141
|
-
|
|
175
|
+
**CONTRACT:** Do not access the second iterator until
|
|
176
|
+
the first one is completely exhausted.
|
|
142
177
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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.
|
|
146
182
|
|
|
147
183
|
"""
|
|
148
184
|
|
|
@@ -160,7 +196,7 @@ def take_while_split[D](
|
|
|
160
196
|
break
|
|
161
197
|
|
|
162
198
|
iterator = iter(iterable)
|
|
163
|
-
|
|
164
|
-
it_pred = _take_while(iterator, pred,
|
|
199
|
+
item: Box[D] = Box()
|
|
200
|
+
it_pred = _take_while(iterator, pred, item)
|
|
165
201
|
|
|
166
|
-
return
|
|
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.
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
"""
|
|
15
|
+
"""
|
|
16
|
+
.. admonition:: Folding and Accumulating
|
|
17
|
+
|
|
18
|
+
Functions to reduce and accumulate items from iterables.
|
|
19
|
+
|
|
20
|
+
"""
|
|
16
21
|
|
|
17
22
|
from collections.abc import Callable, Iterable, Iterator
|
|
18
23
|
from typing import cast, Never
|
|
@@ -34,17 +39,24 @@ __all__ = [
|
|
|
34
39
|
def accumulate[D, L](
|
|
35
40
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
|
|
36
41
|
) -> Iterator[L]:
|
|
37
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
.. admonition:: accumulate
|
|
44
|
+
|
|
45
|
+
Returns an iterator of partial fold items. A pure Python
|
|
46
|
+
version of
|
|
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.
|
|
38
52
|
|
|
39
|
-
|
|
53
|
+
.. note::
|
|
40
54
|
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
A pure Python implementation of the standard
|
|
56
|
+
library's ``itertools.accumulate``
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
:param initial: "optional" initial value to start fold
|
|
47
|
-
:return: an iterator of the intermediate fold values
|
|
58
|
+
- function ``f`` does not default to addition (for typing flexibility)
|
|
59
|
+
- begins accumulation with an optional ``initial`` item
|
|
48
60
|
|
|
49
61
|
"""
|
|
50
62
|
it = iter(iterable)
|
|
@@ -72,21 +84,21 @@ def accumulate[D, L](
|
|
|
72
84
|
|
|
73
85
|
|
|
74
86
|
def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
.. Warning::
|
|
87
|
+
"""
|
|
88
|
+
.. admonition:: reduce left
|
|
78
89
|
|
|
79
|
-
|
|
90
|
+
Fold an iterable left with a function.
|
|
80
91
|
|
|
81
|
-
|
|
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``.
|
|
82
97
|
|
|
83
|
-
|
|
98
|
+
.. warning::
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
:return: reduced value from the iterable
|
|
88
|
-
:raises StopIteration: when called on an empty iterable
|
|
89
|
-
: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``
|
|
90
102
|
|
|
91
103
|
"""
|
|
92
104
|
it = iter(iterable)
|
|
@@ -105,24 +117,24 @@ def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
|
|
|
105
117
|
def fold_left[D, L](
|
|
106
118
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L
|
|
107
119
|
) -> L | Never:
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
- not restricted to ``__add__`` for the folding function
|
|
111
|
-
- initial value required, does not default to ``0`` for initial value
|
|
112
|
-
- handles non-numeric data just find
|
|
120
|
+
"""
|
|
121
|
+
.. admonition:: fold left
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
Fold an iterable left with a function and initial item.
|
|
115
124
|
|
|
116
|
-
|
|
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
|
|
117
128
|
|
|
118
|
-
|
|
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
|
|
119
133
|
|
|
120
|
-
|
|
134
|
+
.. warning::
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
:param initial: mandatory initial value to start fold
|
|
125
|
-
:return: the folded value
|
|
136
|
+
- never returns if given an infinite iterable
|
|
137
|
+
- does not catch or re-raises exceptions raised by ``f``
|
|
126
138
|
|
|
127
139
|
"""
|
|
128
140
|
acc = initial
|
|
@@ -134,24 +146,24 @@ def fold_left[D, L](
|
|
|
134
146
|
def maybe_fold_left[D, L](
|
|
135
147
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
|
|
136
148
|
) -> MayBe[L] | Never:
|
|
137
|
-
"""
|
|
138
|
-
|
|
139
|
-
- when an initial value is not given then ``L = D``
|
|
140
|
-
- if iterable empty and no ``initial`` value given, return ``MayBe()``
|
|
149
|
+
"""
|
|
150
|
+
.. admonition:: maybe fold left
|
|
141
151
|
|
|
142
|
-
|
|
152
|
+
Folds an iterable left with an "optional" initial item.
|
|
143
153
|
|
|
144
|
-
|
|
154
|
+
- when an initial item is not given then ``L = D``
|
|
155
|
+
- if iterable empty and no ``initial`` item given, return ``MayBe()``
|
|
145
156
|
|
|
146
|
-
|
|
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()``.
|
|
147
162
|
|
|
148
|
-
|
|
149
|
-
exception what-so-ever. The exception is thrown away.
|
|
163
|
+
.. warning::
|
|
150
164
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
:param initial: Mandatory initial value to start fold.
|
|
154
|
-
: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
|
|
155
167
|
|
|
156
168
|
"""
|
|
157
169
|
acc: L
|
|
@@ -181,23 +193,33 @@ def sc_reduce_left[D](
|
|
|
181
193
|
include_start: bool = True,
|
|
182
194
|
include_stop: bool = True,
|
|
183
195
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
184
|
-
"""
|
|
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::
|
|
185
212
|
|
|
186
|
-
|
|
213
|
+
Behavior for default arguments will
|
|
187
214
|
|
|
188
|
-
|
|
215
|
+
- left reduce finite iterable
|
|
216
|
+
- start folding immediately
|
|
217
|
+
- continue folding until end (of a possibly infinite iterable)
|
|
189
218
|
|
|
190
|
-
|
|
191
|
-
- start folding immediately
|
|
192
|
-
- continue folding until end (of a possibly infinite iterable)
|
|
219
|
+
.. tip::
|
|
193
220
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
:param start: delay starting the fold until it returns true
|
|
197
|
-
:param stop: prematurely stop the fold when it returns true
|
|
198
|
-
:param include_start: if true, include fold starting value in fold
|
|
199
|
-
:param include_stop: if true, include stopping value in fold
|
|
200
|
-
: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.
|
|
201
223
|
|
|
202
224
|
"""
|
|
203
225
|
it_start = drop_while(iterable, negate(start))
|
|
@@ -233,23 +255,32 @@ def sc_reduce_right[D](
|
|
|
233
255
|
include_start: bool = True,
|
|
234
256
|
include_stop: bool = True,
|
|
235
257
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
236
|
-
"""
|
|
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::
|
|
237
274
|
|
|
238
|
-
|
|
275
|
+
Behavior for default arguments will
|
|
239
276
|
|
|
240
|
-
|
|
277
|
+
- right reduce finite iterable
|
|
278
|
+
- start folding at end (of a possibly infinite iterable)
|
|
279
|
+
- continue reducing right until beginning
|
|
241
280
|
|
|
242
|
-
|
|
243
|
-
- start folding at end (of a possibly infinite iterable)
|
|
244
|
-
- continue reducing right until beginning
|
|
281
|
+
.. tip::
|
|
245
282
|
|
|
246
|
-
|
|
247
|
-
:param f: two parameter function, second parameter for accumulated value
|
|
248
|
-
:param start: delay starting the fold until it returns true
|
|
249
|
-
:param stop: prematurely stop the fold when it returns true
|
|
250
|
-
:param include_start: if true, include fold starting value in fold
|
|
251
|
-
:param include_stop: if true, include stopping value in fold
|
|
252
|
-
:return: tuple of a MayBe of the folded value and iterator of remaining iterables
|
|
283
|
+
Useful for infinite and non-reversible iterables.
|
|
253
284
|
|
|
254
285
|
"""
|
|
255
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.
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
"""
|
|
15
|
+
"""
|
|
16
|
+
.. admonition:: Merging iterables
|
|
17
|
+
|
|
18
|
+
Functions to merge multiple iterables together into one.
|
|
19
|
+
|
|
20
|
+
"""
|
|
16
21
|
|
|
17
22
|
from collections.abc import Iterable, Iterator
|
|
18
23
|
from enum import auto, Enum
|
|
@@ -27,98 +32,112 @@ __all__ = [
|
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
class MergeEnum(Enum):
|
|
30
|
-
"""
|
|
35
|
+
"""
|
|
36
|
+
.. admonition:: Iterable Blending Enums.
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
- **MergeEnum.Concat:** Concatenate first to last
|
|
39
|
+
- **MergeEnum.Merge:** Merge until one is exhausted
|
|
40
|
+
- **MergeEnum.Exhaust:** Merge until all are exhausted
|
|
35
41
|
|
|
36
42
|
"""
|
|
37
|
-
|
|
38
43
|
Concat = auto()
|
|
39
44
|
Merge = auto()
|
|
40
45
|
Exhaust = auto()
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
def concat[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
44
|
-
"""
|
|
49
|
+
"""
|
|
50
|
+
.. admonition:: concatenate iterables
|
|
51
|
+
|
|
52
|
+
Sequentially concatenate multiple iterables.
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
yielding any values.
|
|
54
|
+
:param iterables: Iterables to concatenate.
|
|
55
|
+
:yields: The concatenated items from all the iterables.
|
|
49
56
|
|
|
50
|
-
|
|
57
|
+
.. warning::
|
|
58
|
+
An infinite iterable will prevent subsequent iterables from
|
|
59
|
+
yielding any items.
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
.. note::
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
:returns: Iterator of concatenated values from the iterables.
|
|
63
|
+
Performant to the standard library's ``itertools.chain``.
|
|
56
64
|
|
|
57
65
|
"""
|
|
58
66
|
for iterator in map(lambda x: iter(x), iterables):
|
|
59
67
|
while True:
|
|
60
68
|
try:
|
|
61
|
-
|
|
62
|
-
yield
|
|
69
|
+
item = next(iterator)
|
|
70
|
+
yield item
|
|
63
71
|
except StopIteration:
|
|
64
72
|
break
|
|
65
73
|
|
|
66
74
|
|
|
67
75
|
def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]:
|
|
68
|
-
"""
|
|
76
|
+
"""
|
|
77
|
+
.. admonition:: merge iterables
|
|
69
78
|
|
|
70
|
-
|
|
79
|
+
Merge multiple iterables until one is exhausted.
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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.
|
|
75
85
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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.
|
|
79
94
|
|
|
80
95
|
"""
|
|
81
96
|
iter_list = list(map(lambda x: iter(x), iterables))
|
|
82
|
-
|
|
97
|
+
items = []
|
|
83
98
|
if (num_iters := len(iter_list)) > 0:
|
|
84
99
|
while True:
|
|
85
100
|
try:
|
|
86
101
|
for ii in range(num_iters):
|
|
87
|
-
|
|
88
|
-
yield from
|
|
89
|
-
|
|
102
|
+
items.append(next(iter_list[ii]))
|
|
103
|
+
yield from items
|
|
104
|
+
items.clear()
|
|
90
105
|
except StopIteration:
|
|
91
106
|
break
|
|
92
107
|
if yield_partials:
|
|
93
|
-
yield from
|
|
108
|
+
yield from items
|
|
94
109
|
|
|
95
110
|
|
|
96
111
|
def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
97
|
-
"""
|
|
112
|
+
"""
|
|
113
|
+
.. admonition:: exhaustively merge iterables
|
|
98
114
|
|
|
99
|
-
|
|
100
|
-
|
|
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.
|
|
101
120
|
|
|
102
121
|
"""
|
|
103
122
|
iter_list = list(map(lambda x: iter(x), iterables))
|
|
104
123
|
if (num_iters := len(iter_list)) > 0:
|
|
105
124
|
ii = 0
|
|
106
|
-
|
|
125
|
+
items = []
|
|
107
126
|
while True:
|
|
108
127
|
try:
|
|
109
128
|
while ii < num_iters:
|
|
110
|
-
|
|
129
|
+
items.append(next(iter_list[ii]))
|
|
111
130
|
ii += 1
|
|
112
|
-
yield from
|
|
131
|
+
yield from items
|
|
113
132
|
ii = 0
|
|
114
|
-
|
|
133
|
+
items.clear()
|
|
115
134
|
except StopIteration:
|
|
116
135
|
num_iters -= 1
|
|
117
136
|
if num_iters < 1:
|
|
118
137
|
break
|
|
119
138
|
del iter_list[ii]
|
|
120
139
|
|
|
121
|
-
yield from
|
|
140
|
+
yield from items
|
|
122
141
|
|
|
123
142
|
|
|
124
143
|
def blend[D](
|
|
@@ -126,13 +145,16 @@ def blend[D](
|
|
|
126
145
|
merge_enum: MergeEnum = MergeEnum.Concat,
|
|
127
146
|
yield_partials: bool = False,
|
|
128
147
|
) -> Iterator[D]:
|
|
129
|
-
"""
|
|
148
|
+
"""
|
|
149
|
+
.. admonition:: merge iterables
|
|
150
|
+
|
|
151
|
+
Merge behavior based on value of merge_enum parameter.
|
|
130
152
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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.
|
|
136
158
|
|
|
137
159
|
"""
|
|
138
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
|
-
Requires-Dist: pythonic-fp-fptools>=5.
|
|
18
|
-
Requires-Dist: pythonic-fp-gadgets>=
|
|
17
|
+
Requires-Dist: pythonic-fp-fptools>=5.2.0
|
|
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=UTde8stsDVG_5Z7fo37yiYeTu8fhkkv0QsQcQb_ixTU,1590
|
|
2
|
-
pythonic_fp/iterables/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
pythonic_fp/iterables/drop_take.py,sha256=VpcnQp0Nr4bUGXb-TD2UFl5kHo1fllAFoV_hlYHo8G0,4772
|
|
4
|
-
pythonic_fp/iterables/drop_take.pyi,sha256=vPyByY4PxCGEuL6trI0aTK8fBr4xCuOgqhaKALwJ5Ys,653
|
|
5
|
-
pythonic_fp/iterables/folding.py,sha256=lUvQzRU1wFbolw-b3bI1oU_xk7yIj2V5J8WA-qQxvUc,8612
|
|
6
|
-
pythonic_fp/iterables/folding.pyi,sha256=ZVrpB-D4kWoVwpCsQ2rc3GJ8iTzavAOQ5YK9LteAukU,1175
|
|
7
|
-
pythonic_fp/iterables/merging.py,sha256=CiBYp-iAr-iQrVTWK0wOkFDs9EJ9139p_MRiffIZJ2s,4485
|
|
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.2.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
11
|
-
pythonic_fp_iterables-5.1.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
12
|
-
pythonic_fp_iterables-5.1.2.dist-info/METADATA,sha256=G2d_xgzY-1WoYRBu-QoJbAO9PbV5O3uzcchy9fOO6ho,2143
|
|
13
|
-
pythonic_fp_iterables-5.1.2.dist-info/RECORD,,
|
|
File without changes
|
{pythonic_fp_iterables-5.1.2.dist-info → pythonic_fp_iterables-5.1.4.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|