pythonic-fp.iterables 4.0.0__py3-none-any.whl → 5.1.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 +42 -0
- pythonic_fp/iterables/drop_take.py +165 -0
- pythonic_fp/iterables/drop_take.pyi +33 -0
- pythonic_fp/iterables/folding.py +280 -0
- pythonic_fp/iterables/folding.pyi +56 -0
- pythonic_fp/iterables/merging.py +146 -0
- pythonic_fp/iterables/merging.pyi +38 -0
- pythonic_fp/iterables/py.typed +0 -0
- pythonic_fp_iterables-5.1.0.dist-info/METADATA +61 -0
- pythonic_fp_iterables-5.1.0.dist-info/RECORD +12 -0
- pythonic_fp/iterables.py +0 -653
- pythonic_fp_iterables-4.0.0.dist-info/METADATA +0 -57
- pythonic_fp_iterables-4.0.0.dist-info/RECORD +0 -5
- {pythonic_fp_iterables-4.0.0.dist-info → pythonic_fp_iterables-5.1.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_iterables-4.0.0.dist-info → pythonic_fp_iterables-5.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Copyright 2023-2025 Geoffrey R. Scheller
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Module pythonic_fp.iterables.merging"""
|
|
16
|
+
|
|
17
|
+
from collections.abc import Iterable, Iterator
|
|
18
|
+
from enum import auto, Enum
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
'MergeEnum',
|
|
22
|
+
'concat',
|
|
23
|
+
'merge',
|
|
24
|
+
'exhaust',
|
|
25
|
+
'blend',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MergeEnum(Enum):
|
|
30
|
+
"""Iterable Blending Enums.
|
|
31
|
+
|
|
32
|
+
- **MergeEnum.Concat:** Concatenate first to last
|
|
33
|
+
- **MergeEnum.Merge:** Merge until one is exhausted
|
|
34
|
+
- **MergeEnum.Exhaust:** Merge until all are exhausted
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
Concat = auto()
|
|
39
|
+
Merge = auto()
|
|
40
|
+
Exhaust = auto()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def concat[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
44
|
+
"""Sequentially concatenate multiple iterables together.
|
|
45
|
+
|
|
46
|
+
.. warning::
|
|
47
|
+
An infinite iterable will prevent subsequent iterables from
|
|
48
|
+
yielding any values.
|
|
49
|
+
|
|
50
|
+
.. note::
|
|
51
|
+
|
|
52
|
+
Performant to the standard library's ``itertools.chain``.
|
|
53
|
+
|
|
54
|
+
:param iterables: iterables to concatenate
|
|
55
|
+
:return: iterator of concatenated values from the iterables
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
for iterator in map(lambda x: iter(x), iterables):
|
|
59
|
+
while True:
|
|
60
|
+
try:
|
|
61
|
+
value = next(iterator)
|
|
62
|
+
yield value
|
|
63
|
+
except StopIteration:
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]:
|
|
68
|
+
"""Merge together ``iterables`` until one is exhausted.
|
|
69
|
+
|
|
70
|
+
.. note::
|
|
71
|
+
|
|
72
|
+
When ``yield_partials`` is true, then any unmatched values from other iterables
|
|
73
|
+
already yielded when the first iterable is exhausted are yielded. This prevents
|
|
74
|
+
data lose if any of the iterables are iterators with external references.
|
|
75
|
+
|
|
76
|
+
:param iterables: iterables to merge until one gets exhausted
|
|
77
|
+
:param yield_partials: yield any unpaired yielded values from other iterables
|
|
78
|
+
:return: iterator of merged values from the iterables until one is exhausted
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
iter_list = list(map(lambda x: iter(x), iterables))
|
|
82
|
+
values = []
|
|
83
|
+
if (num_iters := len(iter_list)) > 0:
|
|
84
|
+
while True:
|
|
85
|
+
try:
|
|
86
|
+
for ii in range(num_iters):
|
|
87
|
+
values.append(next(iter_list[ii]))
|
|
88
|
+
yield from values
|
|
89
|
+
values.clear()
|
|
90
|
+
except StopIteration:
|
|
91
|
+
break
|
|
92
|
+
if yield_partials:
|
|
93
|
+
yield from values
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]:
|
|
97
|
+
"""Merge together multiple iterables until all are exhausted.
|
|
98
|
+
|
|
99
|
+
:param iterables: iterables to exhaustively merge
|
|
100
|
+
:return: iterator of merged values from the iterables until all are exhausted
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
iter_list = list(map(lambda x: iter(x), iterables))
|
|
104
|
+
if (num_iters := len(iter_list)) > 0:
|
|
105
|
+
ii = 0
|
|
106
|
+
values = []
|
|
107
|
+
while True:
|
|
108
|
+
try:
|
|
109
|
+
while ii < num_iters:
|
|
110
|
+
values.append(next(iter_list[ii]))
|
|
111
|
+
ii += 1
|
|
112
|
+
yield from values
|
|
113
|
+
ii = 0
|
|
114
|
+
values.clear()
|
|
115
|
+
except StopIteration:
|
|
116
|
+
num_iters -= 1
|
|
117
|
+
if num_iters < 1:
|
|
118
|
+
break
|
|
119
|
+
del iter_list[ii]
|
|
120
|
+
|
|
121
|
+
yield from values
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def blend[D](
|
|
125
|
+
*iterables: Iterable[D],
|
|
126
|
+
merge_enum: MergeEnum = MergeEnum.Concat,
|
|
127
|
+
yield_partials: bool = False,
|
|
128
|
+
) -> Iterator[D]:
|
|
129
|
+
"""Base merge behavior on name only parameters.
|
|
130
|
+
|
|
131
|
+
:param iterables: iterables to blend together
|
|
132
|
+
:param merge_enum: MergeEnum to determine merging behavior
|
|
133
|
+
:param yield_partials: yield yielded unpaired values from other iterables
|
|
134
|
+
:return: an iterator of type D
|
|
135
|
+
:raises ValueError: when an unknown MergeEnum is given
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
match merge_enum:
|
|
139
|
+
case MergeEnum.Concat:
|
|
140
|
+
return concat(*iterables)
|
|
141
|
+
case MergeEnum.Merge:
|
|
142
|
+
return merge(*iterables, yield_partials=yield_partials)
|
|
143
|
+
case MergeEnum.Exhaust:
|
|
144
|
+
return exhaust(*iterables)
|
|
145
|
+
|
|
146
|
+
raise ValueError('Unknown MergeEnum given')
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright 2023-2025 Geoffrey R. Scheller
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from collections.abc import Iterable, Iterator
|
|
16
|
+
from enum import auto, Enum
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
'MergeEnum',
|
|
20
|
+
'concat',
|
|
21
|
+
'merge',
|
|
22
|
+
'exhaust',
|
|
23
|
+
'blend',
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
class MergeEnum(Enum):
|
|
27
|
+
Concat = auto()
|
|
28
|
+
Merge = auto()
|
|
29
|
+
Exhaust = auto()
|
|
30
|
+
|
|
31
|
+
def concat[D](*iterables: Iterable[D]) -> Iterator[D]: ...
|
|
32
|
+
def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]: ...
|
|
33
|
+
def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]: ...
|
|
34
|
+
def blend[D](
|
|
35
|
+
*iterables: Iterable[D],
|
|
36
|
+
merge_enum: MergeEnum = MergeEnum.Concat,
|
|
37
|
+
yield_partials: bool = False,
|
|
38
|
+
) -> Iterator[D]: ...
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pythonic-fp-iterables
|
|
3
|
+
Version: 5.1.0
|
|
4
|
+
Summary: Library of functions for iterating iterables
|
|
5
|
+
Keywords: iterables,iterators
|
|
6
|
+
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
|
+
Requires-Python: >=3.13
|
|
8
|
+
Description-Content-Type: text/x-rst
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Framework :: Pytest
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: pythonic-fp-fptools>=5.1.0
|
|
18
|
+
Requires-Dist: pythonic-fp-gadgets>=3.0.1
|
|
19
|
+
Requires-Dist: pythonic-fp-sentinels>=2.1.1
|
|
20
|
+
Requires-Dist: pytest>=8.4.1 ; extra == "test"
|
|
21
|
+
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-iterables/blob/main/CHANGELOG.rst
|
|
22
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/iterables/development/build/html/releases.html
|
|
23
|
+
Project-URL: Homepage, https://github.com/grscheller/pythonic-fp/blob/main/README.md
|
|
24
|
+
Project-URL: Source, https://github.com/grscheller/pythonic-fp-iterables
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
|
|
27
|
+
Pythonic FP - Tools for iterables
|
|
28
|
+
=================================
|
|
29
|
+
|
|
30
|
+
PyPI project
|
|
31
|
+
`pythonic-fp.iterators <https://pypi.org/project/pythonic-fp.iterables>`_.
|
|
32
|
+
|
|
33
|
+
Library of functions for iterating iterables.
|
|
34
|
+
|
|
35
|
+
- Concatenating and merging iterables
|
|
36
|
+
- Dropping and taking values from iterables
|
|
37
|
+
- Reducing and accumulating iterables
|
|
38
|
+
- Assumptions
|
|
39
|
+
|
|
40
|
+
- iterables are not necessarily iterators
|
|
41
|
+
- at all times iterator protocol is assumed to be followed
|
|
42
|
+
|
|
43
|
+
- all iterators are assumed to be iterable
|
|
44
|
+
- for all iterators ``foo`` we assume ``iter(foo) is foo``
|
|
45
|
+
|
|
46
|
+
This PyPI project is part of of the
|
|
47
|
+
`pythonic-fp namespace projects <https://github.com/grscheller/pythonic-fp/blob/main/README.md>`_
|
|
48
|
+
|
|
49
|
+
Documentation
|
|
50
|
+
-------------
|
|
51
|
+
|
|
52
|
+
Documentation for this project is hosted on
|
|
53
|
+
`GitHub Pages
|
|
54
|
+
<https://grscheller.github.io/pythonic-fp/iterables/development/build/html>`_.
|
|
55
|
+
|
|
56
|
+
Copyright and License
|
|
57
|
+
---------------------
|
|
58
|
+
|
|
59
|
+
Copyright (c) 2023-2025 Geoffrey R. Scheller. Licensed under the Apache
|
|
60
|
+
License, Version 2.0. See the LICENSE file for details.
|
|
61
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pythonic_fp/iterables/__init__.py,sha256=UTde8stsDVG_5Z7fo37yiYeTu8fhkkv0QsQcQb_ixTU,1590
|
|
2
|
+
pythonic_fp/iterables/drop_take.py,sha256=bHxVTJAY9vof570cFQNXNZZAUAtnWBDZgRu7df2aV9E,4707
|
|
3
|
+
pythonic_fp/iterables/drop_take.pyi,sha256=6BtavkUHIxMJmJfcvDAnds9R29OXrCRkDK12jG575VY,1276
|
|
4
|
+
pythonic_fp/iterables/folding.py,sha256=A4VoU7piryt6Fun6Inn1SJSr1IiN-aTqzeSs-mds5oQ,8604
|
|
5
|
+
pythonic_fp/iterables/folding.pyi,sha256=BUslV-cn9eOxlYAF_3wz09TcHDbMATUL0uqU7IjJyAM,2035
|
|
6
|
+
pythonic_fp/iterables/merging.py,sha256=tPVjw5Fr32gMTd4Uq3SKQPqdV9p5fs3xW-0elt8Yz8U,4462
|
|
7
|
+
pythonic_fp/iterables/merging.pyi,sha256=5QBH0NEoqWQwCvWMPBFVoUOWAwmMYqj2W4s2b1rn9J0,1189
|
|
8
|
+
pythonic_fp/iterables/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
pythonic_fp_iterables-5.1.0.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
10
|
+
pythonic_fp_iterables-5.1.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
11
|
+
pythonic_fp_iterables-5.1.0.dist-info/METADATA,sha256=FjgztLEfjG2VBYMtg_XUa0gyZTplavSKb523m746npY,2218
|
|
12
|
+
pythonic_fp_iterables-5.1.0.dist-info/RECORD,,
|