pythonic-fp.iterables 5.1.3__py3-none-any.whl → 5.2.0__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 +102 -77
- pythonic_fp/iterables/merging.py +65 -47
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.2.0.dist-info}/METADATA +24 -33
- pythonic_fp_iterables-5.2.0.dist-info/RECORD +9 -0
- pythonic_fp/iterables/__init__.pyi +0 -0
- pythonic_fp/iterables/drop_take.pyi +0 -10
- pythonic_fp/iterables/folding.pyi +0 -13
- pythonic_fp/iterables/merging.pyi +0 -14
- pythonic_fp_iterables-5.1.3.dist-info/RECORD +0 -13
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.2.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_iterables-5.1.3.dist-info → pythonic_fp_iterables-5.2.0.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 ``foo`` we assume ``iter(foo) is foo``
|
|
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 valued function.
|
|
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.
|
|
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
|
+
**IMPORTANT:** 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
|
+
**IMPORTANT:** 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 partially folded items.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
:param iterable: Iterable to be folded.
|
|
48
|
+
:param f: Two parameter function, first parameter is for
|
|
49
|
+
the accumulator.
|
|
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,22 @@ 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 is for
|
|
94
|
+
the accumulator.
|
|
95
|
+
:return: Reduced item from the iterable.
|
|
96
|
+
:raises StopIteration: When called on an empty iterable.
|
|
97
|
+
:raises Exception: Does not catch any exceptions from ``f``.
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
.. warning::
|
|
92
100
|
|
|
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``
|
|
101
|
+
- never returns if given an infinite iterable
|
|
102
|
+
- does not catch or re-raise exceptions raised by ``f``
|
|
98
103
|
|
|
99
104
|
"""
|
|
100
105
|
it = iter(iterable)
|
|
@@ -113,24 +118,25 @@ def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
|
|
|
113
118
|
def fold_left[D, L](
|
|
114
119
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L
|
|
115
120
|
) -> 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
|
|
121
|
+
"""
|
|
122
|
+
.. admonition:: fold left
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
Fold an iterable left with a function and initial item.
|
|
123
125
|
|
|
124
|
-
|
|
126
|
+
- not restricted to ``__add__`` for the folding function
|
|
127
|
+
- initial item is required, does not default to ``0``
|
|
128
|
+
- handles non-numeric data just find
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
:param iterable: Iterable to be folded.
|
|
131
|
+
:param f: Two parameter function, first parameter is for
|
|
132
|
+
the accumulator.
|
|
133
|
+
:param initial: Mandatory initial item to start fold
|
|
134
|
+
:return: The folded item.
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
.. warning::
|
|
129
137
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
:param initial: mandatory initial value to start fold
|
|
133
|
-
:return: the folded value
|
|
138
|
+
- never returns if given an infinite iterable
|
|
139
|
+
- does not catch or re-raises exceptions raised by ``f``
|
|
134
140
|
|
|
135
141
|
"""
|
|
136
142
|
acc = initial
|
|
@@ -142,24 +148,24 @@ def fold_left[D, L](
|
|
|
142
148
|
def maybe_fold_left[D, L](
|
|
143
149
|
iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
|
|
144
150
|
) -> 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()``
|
|
151
|
+
"""
|
|
152
|
+
.. admonition:: maybe fold left
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
Folds an iterable left with an "optional" initial item.
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
- when an initial item is not given then ``L = D``
|
|
157
|
+
- if iterable empty and no ``initial`` item given, return ``MayBe()``
|
|
153
158
|
|
|
154
|
-
|
|
159
|
+
:param iterable: The iterable to be folded.
|
|
160
|
+
:param f: First argument is for the accumulator.
|
|
161
|
+
:param initial: Mandatory initial item to start fold.
|
|
162
|
+
:return: ``MayBe`` of a successfully folded item,
|
|
163
|
+
otherwise returns ``MayBe()``.
|
|
155
164
|
|
|
156
|
-
|
|
157
|
-
exception what-so-ever. The exception is thrown away.
|
|
165
|
+
.. warning::
|
|
158
166
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
:param initial: Mandatory initial value to start fold.
|
|
162
|
-
:return: MayBe of a successfully folded value, otherwise MayBe()
|
|
167
|
+
- never returns if given an infinite iterable
|
|
168
|
+
- any exception ``f`` raises is thrown away
|
|
163
169
|
|
|
164
170
|
"""
|
|
165
171
|
acc: L
|
|
@@ -189,23 +195,33 @@ def sc_reduce_left[D](
|
|
|
189
195
|
include_start: bool = True,
|
|
190
196
|
include_stop: bool = True,
|
|
191
197
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
192
|
-
"""
|
|
198
|
+
"""
|
|
199
|
+
.. admonition:: short circuit reduce left
|
|
200
|
+
|
|
201
|
+
Short circuit version of a left fold.
|
|
202
|
+
|
|
203
|
+
:param iterable: Iterable to be reduced from the left.
|
|
204
|
+
:param f: Two parameter function, first parameter is for
|
|
205
|
+
the accumulator.
|
|
206
|
+
:param start: Delay starting the fold until it returns true.
|
|
207
|
+
:param stop: Prematurely stop the fold when it returns true.
|
|
208
|
+
:param include_start: If true, include starting item in fold.
|
|
209
|
+
:param include_stop: If true, include stopping item in fold.
|
|
210
|
+
:return: Tuple of a ``MayBe`` of the folded item and iterator
|
|
211
|
+
of remaining iterables.
|
|
212
|
+
|
|
213
|
+
.. note::
|
|
193
214
|
|
|
194
|
-
|
|
215
|
+
Behavior for default arguments will
|
|
195
216
|
|
|
196
|
-
|
|
217
|
+
- left reduce finite iterable
|
|
218
|
+
- start folding immediately
|
|
219
|
+
- continue folding until end (of a possibly infinite iterable)
|
|
197
220
|
|
|
198
|
-
|
|
199
|
-
- start folding immediately
|
|
200
|
-
- continue folding until end (of a possibly infinite iterable)
|
|
221
|
+
.. tip::
|
|
201
222
|
|
|
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
|
|
223
|
+
Useful for infinite iterables when Callable ``stop``
|
|
224
|
+
is provided.
|
|
209
225
|
|
|
210
226
|
"""
|
|
211
227
|
it_start = drop_while(iterable, negate(start))
|
|
@@ -241,23 +257,32 @@ def sc_reduce_right[D](
|
|
|
241
257
|
include_start: bool = True,
|
|
242
258
|
include_stop: bool = True,
|
|
243
259
|
) -> tuple[MayBe[D], Iterator[D]]:
|
|
244
|
-
"""
|
|
260
|
+
"""
|
|
261
|
+
.. admonition:: short circuit reduce right
|
|
262
|
+
|
|
263
|
+
Short circuit version of a right fold.
|
|
264
|
+
|
|
265
|
+
:param iterable: Iterable to be reduced from the right.
|
|
266
|
+
:param f: Two parameter function, second parameter is for
|
|
267
|
+
the accumulator.
|
|
268
|
+
:param start: Delay starting the fold until it returns true.
|
|
269
|
+
:param stop: Prematurely stop the fold when it returns true.
|
|
270
|
+
:param include_start: If true, include starting item.
|
|
271
|
+
:param include_stop: If true, include stopping item in fold.
|
|
272
|
+
:return: Tuple of a ``MayBe`` of the folded item and iterator
|
|
273
|
+
of remaining iterables.
|
|
274
|
+
|
|
275
|
+
.. note::
|
|
245
276
|
|
|
246
|
-
|
|
277
|
+
Behavior for default arguments will
|
|
247
278
|
|
|
248
|
-
|
|
279
|
+
- right reduce finite iterable
|
|
280
|
+
- start folding at end (of a possibly infinite iterable)
|
|
281
|
+
- continue reducing right until beginning
|
|
249
282
|
|
|
250
|
-
|
|
251
|
-
- start folding at end (of a possibly infinite iterable)
|
|
252
|
-
- continue reducing right until beginning
|
|
283
|
+
.. tip::
|
|
253
284
|
|
|
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
|
|
285
|
+
Useful for infinite and non-reversible iterables.
|
|
261
286
|
|
|
262
287
|
"""
|
|
263
288
|
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
|
+
- **Concat:** Concatenate first to last
|
|
39
|
+
- **Merge:** Merge until one is exhausted
|
|
40
|
+
- **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
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
An infinite iterable will prevent subsequent iterables from
|
|
56
|
-
yielding any values.
|
|
52
|
+
Sequentially concatenate multiple iterables.
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
:param iterables: Iterables to concatenate.
|
|
55
|
+
:yields: The concatenated items from all the iterables.
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
.. warning::
|
|
58
|
+
An infinite iterable will prevent subsequent iterables from
|
|
59
|
+
yielding any items.
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
.. note::
|
|
62
|
+
|
|
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
|
|
78
|
+
|
|
79
|
+
Merge multiple iterables until one of them is exhausted.
|
|
77
80
|
|
|
78
|
-
|
|
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.
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
already yielded when the first iterable is exhausted are yielded. This prevents
|
|
82
|
-
data lose if any of the iterables are iterators with external references.
|
|
86
|
+
.. note::
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
114
|
+
|
|
115
|
+
Merge multiple iterables until all of them are exhausted.
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
|
|
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,20 @@ 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.
|
|
152
|
+
|
|
153
|
+
- Concat: Concatenate first to last
|
|
154
|
+
- Merge: Merge until one is exhausted
|
|
155
|
+
- Exhaust: Merge until all are exhausted
|
|
138
156
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
:param iterables: Iterables to blend together.
|
|
158
|
+
:param merge_enum: ``MergeEnum`` to determine merging behavior.
|
|
159
|
+
:param yield_partials: Yield unpaired items from other iterables.
|
|
160
|
+
:yields: Items from all iterables blended together.
|
|
161
|
+
:raises ValueError: When an unknown ``MergeEnum`` is given.
|
|
144
162
|
|
|
145
163
|
"""
|
|
146
164
|
match merge_enum:
|
|
@@ -1,62 +1,53 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-iterables
|
|
3
|
-
Version: 5.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 5.2.0
|
|
4
|
+
Summary: Composing and iterating iterables.
|
|
5
5
|
Keywords: iterables,iterators
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
|
-
Requires-Python: >=3.
|
|
8
|
-
Description-Content-Type: text/
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
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
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
16
|
Classifier: Typing :: Typed
|
|
16
17
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: pythonic-fp-fptools>=
|
|
18
|
-
Requires-Dist: pythonic-fp-gadgets>=4.
|
|
19
|
-
|
|
20
|
-
Project-URL:
|
|
21
|
-
Project-URL:
|
|
22
|
-
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/homepage/build/html/
|
|
18
|
+
Requires-Dist: pythonic-fp-fptools>=6,<6.2
|
|
19
|
+
Requires-Dist: pythonic-fp-gadgets>=4.5,<6
|
|
20
|
+
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-iterables/blob/main/CHANGELOG.md
|
|
21
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp-iterables/release/html/
|
|
22
|
+
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
23
23
|
Project-URL: Source, https://github.com/grscheller/pythonic-fp-iterables
|
|
24
|
-
Provides-Extra: test
|
|
25
24
|
|
|
26
|
-
Pythonic FP - Tools for iterables
|
|
27
|
-
|
|
25
|
+
# Pythonic FP - Tools for iterables
|
|
26
|
+
|
|
27
|
+
Library of functions for iterating iterables.
|
|
28
28
|
|
|
29
29
|
PyPI project
|
|
30
|
-
|
|
30
|
+
[pythonic-fp-iterators](https://pypi.org/project/pythonic-fp-iterables).
|
|
31
|
+
Part of the
|
|
32
|
+
[pythonic-fp](https://grscheller.github.io/pythonic-fp/)
|
|
33
|
+
PyPI projects.
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
## Documentation
|
|
36
|
+
|
|
37
|
+
Documentation and other links for this project are hosted on
|
|
38
|
+
[GitHub Pages](https://grscheller.github.io/pythonic-fp/projects/iterables.html).
|
|
33
39
|
|
|
34
40
|
- Concatenating and merging iterables
|
|
35
41
|
- Dropping and taking values from iterables
|
|
36
42
|
- Reducing and accumulating iterables
|
|
37
43
|
- Assumptions
|
|
38
|
-
|
|
39
44
|
- iterables are not necessarily iterators
|
|
40
45
|
- at all times iterator protocol is assumed to be followed
|
|
41
|
-
|
|
42
46
|
- all iterators are assumed to be iterable
|
|
43
47
|
- for all iterators ``foo`` we assume ``iter(foo) is foo``
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
`pythonic-fp
|
|
47
|
-
<https://grscheller.github.io/pythonic-fp>`_
|
|
48
|
-
PyPI projects.
|
|
49
|
-
|
|
50
|
-
Documentation
|
|
51
|
-
-------------
|
|
52
|
-
|
|
53
|
-
Documentation for this project is hosted on
|
|
54
|
-
`GitHub Pages
|
|
55
|
-
<https://grscheller.github.io/pythonic-fp/iterables>`_.
|
|
56
|
-
|
|
57
|
-
Copyright and License
|
|
58
|
-
---------------------
|
|
49
|
+
## Copyright and License
|
|
59
50
|
|
|
60
|
-
Copyright (c) 2023-
|
|
51
|
+
Copyright (c) 2023-2026 Geoffrey R. Scheller. Licensed under the Apache
|
|
61
52
|
License, Version 2.0. See the LICENSE file for details.
|
|
62
53
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
pythonic_fp/iterables/__init__.py,sha256=lL6SETAAn9sn2dGRBxvbJlswZwweym4OumCKbJfokQI,1246
|
|
2
|
+
pythonic_fp/iterables/drop_take.py,sha256=kZS8paCc-EOD42BGmCg-89e0W9CGFCXiB88Y4oE_lSg,5527
|
|
3
|
+
pythonic_fp/iterables/folding.py,sha256=IZmoWyuh8D9rS_g9K8DhSu_owM1_IJ_oIMsLJNqH28I,9377
|
|
4
|
+
pythonic_fp/iterables/merging.py,sha256=YYXrCNXHF9xuIMLOySTube6-_YUNB2GGirTa8VbpeLM,5038
|
|
5
|
+
pythonic_fp/iterables/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
pythonic_fp_iterables-5.2.0.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
7
|
+
pythonic_fp_iterables-5.2.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
8
|
+
pythonic_fp_iterables-5.2.0.dist-info/METADATA,sha256=yajE7AFhbVcOksI_nW2PdhDdURZjrRkRlpBfBAfiVdw,1997
|
|
9
|
+
pythonic_fp_iterables-5.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
from collections.abc import Callable, Iterable, Iterator
|
|
2
|
-
|
|
3
|
-
__all__ = ['drop', 'drop_while', 'take', 'take_while', 'take_split', 'take_while_split']
|
|
4
|
-
|
|
5
|
-
def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]: ...
|
|
6
|
-
def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]: ...
|
|
7
|
-
def take[D](iterable: Iterable[D], n: int) -> Iterator[D]: ...
|
|
8
|
-
def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]: ...
|
|
9
|
-
def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[D]]: ...
|
|
10
|
-
def take_while_split[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> tuple[Iterator[D], Iterator[D]]: ...
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from collections.abc import Callable, Iterable, Iterator
|
|
2
|
-
from pythonic_fp.fptools.maybe import MayBe
|
|
3
|
-
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
4
|
-
from typing import Never
|
|
5
|
-
|
|
6
|
-
__all__ = ['accumulate', 'reduce_left', 'fold_left', 'maybe_fold_left', 'sc_reduce_left', 'sc_reduce_right']
|
|
7
|
-
|
|
8
|
-
def accumulate[D, L](iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = ...) -> Iterator[L]: ...
|
|
9
|
-
def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never: ...
|
|
10
|
-
def fold_left[D, L](iterable: Iterable[D], f: Callable[[L, D], L], initial: L) -> L | Never: ...
|
|
11
|
-
def maybe_fold_left[D, L](iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = ...) -> MayBe[L] | Never: ...
|
|
12
|
-
def sc_reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D], start: Callable[[D], bool] = ..., stop: Callable[[D], bool] = ..., include_start: bool = True, include_stop: bool = True) -> tuple[MayBe[D], Iterator[D]]: ...
|
|
13
|
-
def sc_reduce_right[D](iterable: Iterable[D], f: Callable[[D, D], D], start: Callable[[D], bool] = ..., stop: Callable[[D], bool] = ..., include_start: bool = True, include_stop: bool = True) -> tuple[MayBe[D], Iterator[D]]: ...
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from collections.abc import Iterable, Iterator
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
|
-
__all__ = ['MergeEnum', 'concat', 'merge', 'exhaust', 'blend']
|
|
5
|
-
|
|
6
|
-
class MergeEnum(Enum):
|
|
7
|
-
Concat = ...
|
|
8
|
-
Merge = ...
|
|
9
|
-
Exhaust = ...
|
|
10
|
-
|
|
11
|
-
def concat[D](*iterables: Iterable[D]) -> Iterator[D]: ...
|
|
12
|
-
def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]: ...
|
|
13
|
-
def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]: ...
|
|
14
|
-
def blend[D](*iterables: Iterable[D], merge_enum: MergeEnum = ..., yield_partials: bool = False) -> Iterator[D]: ...
|
|
@@ -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.2.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|