pyochain 0.5.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.
Potentially problematic release.
This version of pyochain might be problematic. Click here for more details.
- pyochain/__init__.py +5 -0
- pyochain/_core/__init__.py +21 -0
- pyochain/_core/_main.py +184 -0
- pyochain/_core/_protocols.py +43 -0
- pyochain/_dict/__init__.py +4 -0
- pyochain/_dict/_exprs.py +115 -0
- pyochain/_dict/_filters.py +273 -0
- pyochain/_dict/_funcs.py +62 -0
- pyochain/_dict/_groups.py +176 -0
- pyochain/_dict/_iter.py +92 -0
- pyochain/_dict/_joins.py +137 -0
- pyochain/_dict/_main.py +307 -0
- pyochain/_dict/_nested.py +218 -0
- pyochain/_dict/_process.py +171 -0
- pyochain/_iter/__init__.py +3 -0
- pyochain/_iter/_aggregations.py +323 -0
- pyochain/_iter/_booleans.py +224 -0
- pyochain/_iter/_constructors.py +155 -0
- pyochain/_iter/_eager.py +195 -0
- pyochain/_iter/_filters.py +503 -0
- pyochain/_iter/_groups.py +264 -0
- pyochain/_iter/_joins.py +407 -0
- pyochain/_iter/_lists.py +306 -0
- pyochain/_iter/_main.py +224 -0
- pyochain/_iter/_maps.py +358 -0
- pyochain/_iter/_partitions.py +148 -0
- pyochain/_iter/_process.py +384 -0
- pyochain/_iter/_rolling.py +247 -0
- pyochain/_iter/_tuples.py +221 -0
- pyochain/py.typed +0 -0
- pyochain-0.5.0.dist-info/METADATA +295 -0
- pyochain-0.5.0.dist-info/RECORD +33 -0
- pyochain-0.5.0.dist-info/WHEEL +4 -0
pyochain/_iter/_eager.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable
|
|
4
|
+
from functools import partial
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import cytoolz as cz
|
|
8
|
+
|
|
9
|
+
from .._core import IterWrapper, SupportsRichComparison
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ._main import Seq
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseEager[T](IterWrapper[T]):
|
|
16
|
+
def sort[U: SupportsRichComparison[Any]](
|
|
17
|
+
self: BaseEager[U], reverse: bool = False, key: Callable[[U], Any] | None = None
|
|
18
|
+
) -> Seq[U]:
|
|
19
|
+
"""
|
|
20
|
+
Sort the elements of the sequence.
|
|
21
|
+
|
|
22
|
+
Note:
|
|
23
|
+
This method must consume the entire iterable to perform the sort.
|
|
24
|
+
The result is a new iterable over the sorted sequence.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
reverse: Whether to sort in descending order. Defaults to False.
|
|
28
|
+
key: Function to extract a comparison key from each element. Defaults to None.
|
|
29
|
+
Example:
|
|
30
|
+
```python
|
|
31
|
+
>>> import pyochain as pc
|
|
32
|
+
>>> pc.Iter.from_([3, 1, 2]).sort().into(list)
|
|
33
|
+
[1, 2, 3]
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def _sort(data: Iterable[U]) -> list[U]:
|
|
39
|
+
return sorted(data, reverse=reverse, key=key)
|
|
40
|
+
|
|
41
|
+
return self.collect(_sort)
|
|
42
|
+
|
|
43
|
+
def tail(self, n: int) -> Seq[T]:
|
|
44
|
+
"""
|
|
45
|
+
Return a tuple of the last n elements.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
n: Number of elements to return.
|
|
49
|
+
Example:
|
|
50
|
+
```python
|
|
51
|
+
>>> import pyochain as pc
|
|
52
|
+
>>> pc.Iter.from_([1, 2, 3]).tail(2).unwrap()
|
|
53
|
+
(2, 3)
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
"""
|
|
57
|
+
return self.collect(partial(cz.itertoolz.tail, n))
|
|
58
|
+
|
|
59
|
+
def top_n(self, n: int, key: Callable[[T], Any] | None = None) -> Seq[T]:
|
|
60
|
+
"""
|
|
61
|
+
Return a tuple of the top-n items according to key.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
n: Number of top elements to return.
|
|
65
|
+
key: Function to extract a comparison key from each element. Defaults to None.
|
|
66
|
+
Example:
|
|
67
|
+
```python
|
|
68
|
+
>>> import pyochain as pc
|
|
69
|
+
>>> pc.Iter.from_([1, 3, 2]).top_n(2).unwrap()
|
|
70
|
+
(3, 2)
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
"""
|
|
74
|
+
return self.collect(partial(cz.itertoolz.topk, n, key=key))
|
|
75
|
+
|
|
76
|
+
def union(self, *others: Iterable[T]) -> Seq[T]:
|
|
77
|
+
"""
|
|
78
|
+
Return the union of this iterable and 'others'.
|
|
79
|
+
|
|
80
|
+
Note:
|
|
81
|
+
This method consumes inner data and removes duplicates.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
*others: Other iterables to include in the union.
|
|
85
|
+
Example:
|
|
86
|
+
```python
|
|
87
|
+
>>> import pyochain as pc
|
|
88
|
+
>>> pc.Iter.from_([1, 2, 2]).union([2, 3], [4]).iter().sort().unwrap()
|
|
89
|
+
[1, 2, 3, 4]
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def _union(data: Iterable[T]) -> set[T]:
|
|
95
|
+
return set(data).union(*others)
|
|
96
|
+
|
|
97
|
+
return self.collect(_union)
|
|
98
|
+
|
|
99
|
+
def intersection(self, *others: Iterable[T]) -> Seq[T]:
|
|
100
|
+
"""
|
|
101
|
+
Return the elements common to this iterable and 'others'.
|
|
102
|
+
|
|
103
|
+
Note:
|
|
104
|
+
This method consumes inner data, unsorts it, and removes duplicates.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
*others: Other iterables to intersect with.
|
|
108
|
+
Example:
|
|
109
|
+
```python
|
|
110
|
+
>>> import pyochain as pc
|
|
111
|
+
>>> pc.Iter.from_([1, 2, 2]).intersection([2, 3], [2]).unwrap()
|
|
112
|
+
{2}
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def _intersection(data: Iterable[T]) -> set[T]:
|
|
118
|
+
return set(data).intersection(*others)
|
|
119
|
+
|
|
120
|
+
return self.collect(_intersection)
|
|
121
|
+
|
|
122
|
+
def diff_unique(self, *others: Iterable[T]) -> Seq[T]:
|
|
123
|
+
"""
|
|
124
|
+
Return the difference of this iterable and 'others'.
|
|
125
|
+
(Elements in 'self' but not in 'others').
|
|
126
|
+
|
|
127
|
+
Note:
|
|
128
|
+
This method consumes inner data, unsorts it, and removes duplicates.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
*others: Other iterables to subtract from this iterable.
|
|
132
|
+
Example:
|
|
133
|
+
```python
|
|
134
|
+
>>> import pyochain as pc
|
|
135
|
+
>>> pc.Iter.from_([1, 2, 2]).diff_unique([2, 3]).unwrap()
|
|
136
|
+
{1}
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
def _difference(data: Iterable[T]) -> set[T]:
|
|
142
|
+
return set(data).difference(*others)
|
|
143
|
+
|
|
144
|
+
return self.collect(_difference)
|
|
145
|
+
|
|
146
|
+
def diff_symmetric(self, *others: Iterable[T]) -> Seq[T]:
|
|
147
|
+
"""
|
|
148
|
+
Return the symmetric difference (XOR) of this iterable and 'others'.
|
|
149
|
+
|
|
150
|
+
Note:
|
|
151
|
+
This method consumes inner data, unsorts it, and removes duplicates.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
*others: Other iterables to compute the symmetric difference with.
|
|
155
|
+
Example:
|
|
156
|
+
```python
|
|
157
|
+
>>> import pyochain as pc
|
|
158
|
+
>>> pc.Iter.from_([1, 2, 2]).diff_symmetric([2, 3]).iter().sort().unwrap()
|
|
159
|
+
[1, 3]
|
|
160
|
+
>>> pc.Iter.from_([1, 2, 3]).diff_symmetric([3, 4, 5]).iter().sort().unwrap()
|
|
161
|
+
[1, 2, 4, 5]
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
def _symmetric_difference(data: Iterable[T]) -> set[T]:
|
|
167
|
+
return set(data).symmetric_difference(*others)
|
|
168
|
+
|
|
169
|
+
return self.collect(_symmetric_difference)
|
|
170
|
+
|
|
171
|
+
def most_common(self, n: int | None = None) -> Seq[tuple[T, int]]:
|
|
172
|
+
"""
|
|
173
|
+
Return the n most common elements and their counts.
|
|
174
|
+
|
|
175
|
+
If n is None, then all elements are returned.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
n: Number of most common elements to return. Defaults to None (all elements).
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
```python
|
|
182
|
+
>>> import pyochain as pc
|
|
183
|
+
>>> pc.Iter.from_([1, 1, 2, 3, 3, 3]).most_common(2).unwrap()
|
|
184
|
+
[(3, 3), (1, 2)]
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
"""
|
|
188
|
+
from collections import Counter
|
|
189
|
+
|
|
190
|
+
from ._main import Seq
|
|
191
|
+
|
|
192
|
+
def _most_common(data: Iterable[T]) -> list[tuple[T, int]]:
|
|
193
|
+
return Counter(data).most_common(n)
|
|
194
|
+
|
|
195
|
+
return Seq(self.into(_most_common))
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
from collections.abc import Callable, Generator, Iterable, Iterator
|
|
5
|
+
from functools import partial
|
|
6
|
+
from typing import TYPE_CHECKING, Any, TypeGuard
|
|
7
|
+
|
|
8
|
+
import cytoolz as cz
|
|
9
|
+
import more_itertools as mit
|
|
10
|
+
|
|
11
|
+
from .._core import IterWrapper
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ._main import Iter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseFilter[T](IterWrapper[T]):
|
|
18
|
+
def filter(self, func: Callable[[T], bool]) -> Iter[T]:
|
|
19
|
+
"""
|
|
20
|
+
Return an iterator yielding those items of iterable for which function is true.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
func: Function to evaluate each item.
|
|
24
|
+
Example:
|
|
25
|
+
```python
|
|
26
|
+
>>> import pyochain as pc
|
|
27
|
+
>>> pc.Iter.from_([1, 2, 3]).filter(lambda x: x > 1).into(list)
|
|
28
|
+
[2, 3]
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def _filter(data: Iterable[T]) -> Iterator[T]:
|
|
34
|
+
return (x for x in data if func(x))
|
|
35
|
+
|
|
36
|
+
return self.apply(_filter)
|
|
37
|
+
|
|
38
|
+
def filter_isin(self, values: Iterable[T]) -> Iter[T]:
|
|
39
|
+
"""
|
|
40
|
+
Return elements that are in the given values iterable.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
values: Iterable of values to check membership against.
|
|
44
|
+
Example:
|
|
45
|
+
```python
|
|
46
|
+
>>> import pyochain as pc
|
|
47
|
+
>>> pc.Iter.from_([1, 2, 3, 4]).filter_isin([2, 4, 6]).into(list)
|
|
48
|
+
[2, 4]
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def _filter_isin(data: Iterable[T]) -> Generator[T, None, None]:
|
|
54
|
+
value_set: set[T] = set(values)
|
|
55
|
+
return (x for x in data if x in value_set)
|
|
56
|
+
|
|
57
|
+
return self.apply(_filter_isin)
|
|
58
|
+
|
|
59
|
+
def filter_notin(self, values: Iterable[T]) -> Iter[T]:
|
|
60
|
+
"""
|
|
61
|
+
Return elements that are not in the given values iterable.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
values: Iterable of values to exclude.
|
|
65
|
+
Example:
|
|
66
|
+
```python
|
|
67
|
+
>>> import pyochain as pc
|
|
68
|
+
>>> pc.Iter.from_([1, 2, 3, 4]).filter_notin([2, 4, 6]).into(list)
|
|
69
|
+
[1, 3]
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def _filter_notin(data: Iterable[T]) -> Generator[T, None, None]:
|
|
75
|
+
value_set: set[T] = set(values)
|
|
76
|
+
return (x for x in data if x not in value_set)
|
|
77
|
+
|
|
78
|
+
return self.apply(_filter_notin)
|
|
79
|
+
|
|
80
|
+
def filter_contain(
|
|
81
|
+
self: IterWrapper[str], text: str, format: Callable[[str], str] | None = None
|
|
82
|
+
) -> Iter[str]:
|
|
83
|
+
"""
|
|
84
|
+
Return elements that contain the given text.
|
|
85
|
+
|
|
86
|
+
Optionally, a format function can be provided to preprocess each element before checking for the substring.
|
|
87
|
+
Args:
|
|
88
|
+
text: Substring to check for.
|
|
89
|
+
format: Optional function to preprocess each element before checking. Defaults to None.
|
|
90
|
+
Example:
|
|
91
|
+
```python
|
|
92
|
+
>>> import pyochain as pc
|
|
93
|
+
>>>
|
|
94
|
+
>>> data = pc.Seq(["apple", "banana", "cherry", "date"])
|
|
95
|
+
>>> data.iter().filter_contain("ana").into(list)
|
|
96
|
+
['banana']
|
|
97
|
+
>>> data.iter().map(str.upper).filter_contain("ana", str.lower).into(list)
|
|
98
|
+
['BANANA']
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def _filter_contain(data: Iterable[str]) -> Generator[str, None, None]:
|
|
104
|
+
def _(x: str) -> bool:
|
|
105
|
+
formatted = format(x) if format else x
|
|
106
|
+
return text in formatted
|
|
107
|
+
|
|
108
|
+
return (x for x in data if _(x))
|
|
109
|
+
|
|
110
|
+
return self.apply(_filter_contain)
|
|
111
|
+
|
|
112
|
+
def filter_attr[U](self, attr: str, dtype: type[U] = object) -> Iter[U]:
|
|
113
|
+
"""
|
|
114
|
+
Return elements that have the given attribute.
|
|
115
|
+
|
|
116
|
+
The provided dtype is not checked at runtime for performance considerations.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
attr: Name of the attribute to check for.
|
|
120
|
+
dtype: Expected type of the attribute. Defaults to object.
|
|
121
|
+
Example:
|
|
122
|
+
```python
|
|
123
|
+
>>> import pyochain as pc
|
|
124
|
+
>>> pc.Iter.from_(["hello", "world", 2, 5]).filter_attr("capitalize", str).into(
|
|
125
|
+
... list
|
|
126
|
+
... )
|
|
127
|
+
['hello', 'world']
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
def check(data: Iterable[Any]) -> Generator[U, None, None]:
|
|
133
|
+
def _(x: Any) -> TypeGuard[U]:
|
|
134
|
+
return hasattr(x, attr)
|
|
135
|
+
|
|
136
|
+
return (x for x in data if _(x))
|
|
137
|
+
|
|
138
|
+
return self.apply(check)
|
|
139
|
+
|
|
140
|
+
def filter_false(self, func: Callable[[T], bool]) -> Iter[T]:
|
|
141
|
+
"""
|
|
142
|
+
Return elements for which func is false.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
func: Function to evaluate each item.
|
|
146
|
+
Example:
|
|
147
|
+
```python
|
|
148
|
+
>>> import pyochain as pc
|
|
149
|
+
>>> pc.Iter.from_([1, 2, 3]).filter_false(lambda x: x > 1).into(list)
|
|
150
|
+
[1]
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
"""
|
|
154
|
+
return self.apply(partial(itertools.filterfalse, func))
|
|
155
|
+
|
|
156
|
+
def filter_except(
|
|
157
|
+
self, func: Callable[[T], object], *exceptions: type[BaseException]
|
|
158
|
+
) -> Iter[T]:
|
|
159
|
+
"""
|
|
160
|
+
Yield the items from iterable for which the validator function does not raise one of the specified exceptions.
|
|
161
|
+
|
|
162
|
+
Validator is called for each item in iterable.
|
|
163
|
+
|
|
164
|
+
It should be a function that accepts one argument and raises an exception if that item is not valid.
|
|
165
|
+
|
|
166
|
+
If an exception other than one given by exceptions is raised by validator, it is raised like normal.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
func: Validator function to apply to each item.
|
|
170
|
+
exceptions: Exceptions to catch and ignore.
|
|
171
|
+
Example:
|
|
172
|
+
```python
|
|
173
|
+
>>> import pyochain as pc
|
|
174
|
+
>>> iterable = ["1", "2", "three", "4", None]
|
|
175
|
+
>>> pc.Iter.from_(iterable).filter_except(int, ValueError, TypeError).into(list)
|
|
176
|
+
['1', '2', '4']
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
def _filter_except(data: Iterable[T]) -> Iterator[T]:
|
|
182
|
+
return mit.filter_except(func, data, *exceptions)
|
|
183
|
+
|
|
184
|
+
return self.apply(_filter_except)
|
|
185
|
+
|
|
186
|
+
def take_while(self, predicate: Callable[[T], bool]) -> Iter[T]:
|
|
187
|
+
"""
|
|
188
|
+
Take items while predicate holds.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
predicate: Function to evaluate each item.
|
|
192
|
+
Example:
|
|
193
|
+
```python
|
|
194
|
+
>>> import pyochain as pc
|
|
195
|
+
>>> pc.Iter.from_([1, 2, 0]).take_while(lambda x: x > 0).into(list)
|
|
196
|
+
[1, 2]
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
"""
|
|
200
|
+
return self.apply(partial(itertools.takewhile, predicate))
|
|
201
|
+
|
|
202
|
+
def skip_while(self, predicate: Callable[[T], bool]) -> Iter[T]:
|
|
203
|
+
"""
|
|
204
|
+
Drop items while predicate holds.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
predicate: Function to evaluate each item.
|
|
208
|
+
Example:
|
|
209
|
+
```python
|
|
210
|
+
>>> import pyochain as pc
|
|
211
|
+
>>> pc.Iter.from_([1, 2, 0]).skip_while(lambda x: x > 0).into(list)
|
|
212
|
+
[0]
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
"""
|
|
216
|
+
return self.apply(partial(itertools.dropwhile, predicate))
|
|
217
|
+
|
|
218
|
+
def compress(self, *selectors: bool) -> Iter[T]:
|
|
219
|
+
"""
|
|
220
|
+
Filter elements using a boolean selector iterable.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
selectors: Boolean values indicating which elements to keep.
|
|
224
|
+
Example:
|
|
225
|
+
```python
|
|
226
|
+
>>> import pyochain as pc
|
|
227
|
+
>>> pc.Iter.from_("ABCDEF").compress(1, 0, 1, 0, 1, 1).into(list)
|
|
228
|
+
['A', 'C', 'E', 'F']
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
"""
|
|
232
|
+
return self.apply(itertools.compress, selectors)
|
|
233
|
+
|
|
234
|
+
def unique(self, key: Callable[[T], Any] | None = None) -> Iter[T]:
|
|
235
|
+
"""
|
|
236
|
+
Return only unique elements of the iterable.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
key: Function to transform items before comparison. Defaults to None.
|
|
240
|
+
Example:
|
|
241
|
+
```python
|
|
242
|
+
>>> import pyochain as pc
|
|
243
|
+
>>> pc.Iter.from_([1, 2, 3]).unique().into(list)
|
|
244
|
+
[1, 2, 3]
|
|
245
|
+
>>> pc.Iter.from_([1, 2, 1, 3]).unique().into(list)
|
|
246
|
+
[1, 2, 3]
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
Uniqueness can be defined by key keyword
|
|
250
|
+
```python
|
|
251
|
+
>>> pc.Iter.from_(["cat", "mouse", "dog", "hen"]).unique(key=len).into(list)
|
|
252
|
+
['cat', 'mouse']
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
"""
|
|
256
|
+
return self.apply(cz.itertoolz.unique, key=key)
|
|
257
|
+
|
|
258
|
+
def take(self, n: int) -> Iter[T]:
|
|
259
|
+
"""
|
|
260
|
+
Creates an iterator that yields the first n elements, or fewer if the underlying iterator ends sooner.
|
|
261
|
+
|
|
262
|
+
`Iter.take(n)` yields elements until n elements are yielded or the end of the iterator is reached (whichever happens first).
|
|
263
|
+
|
|
264
|
+
The returned iterator is either:
|
|
265
|
+
|
|
266
|
+
- A prefix of length n if the original iterator contains at least n elements
|
|
267
|
+
- All of the (fewer than n) elements of the original iterator if it contains fewer than n elements.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
n: Number of elements to take.
|
|
271
|
+
Example:
|
|
272
|
+
```python
|
|
273
|
+
>>> import pyochain as pc
|
|
274
|
+
>>> data = [1, 2, 3]
|
|
275
|
+
>>> pc.Iter.from_(data).take(2).into(list)
|
|
276
|
+
[1, 2]
|
|
277
|
+
>>> pc.Iter.from_(data).take(5).into(list)
|
|
278
|
+
[1, 2, 3]
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
return self.apply(partial(cz.itertoolz.take, n))
|
|
284
|
+
|
|
285
|
+
def skip(self, n: int) -> Iter[T]:
|
|
286
|
+
"""
|
|
287
|
+
Drop first n elements.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
n: Number of elements to skip.
|
|
291
|
+
Example:
|
|
292
|
+
```python
|
|
293
|
+
>>> import pyochain as pc
|
|
294
|
+
>>> pc.Iter.from_([1, 2, 3]).skip(1).into(list)
|
|
295
|
+
[2, 3]
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
"""
|
|
299
|
+
return self.apply(partial(cz.itertoolz.drop, n))
|
|
300
|
+
|
|
301
|
+
def unique_justseen(self, key: Callable[[T], Any] | None = None) -> Iter[T]:
|
|
302
|
+
"""
|
|
303
|
+
Yields elements in order, ignoring serial duplicates.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
key: Function to transform items before comparison. Defaults to None.
|
|
307
|
+
Example:
|
|
308
|
+
```python
|
|
309
|
+
>>> import pyochain as pc
|
|
310
|
+
>>> pc.Iter.from_("AAAABBBCCDAABBB").unique_justseen().into(list)
|
|
311
|
+
['A', 'B', 'C', 'D', 'A', 'B']
|
|
312
|
+
>>> pc.Iter.from_("ABBCcAD").unique_justseen(str.lower).into(list)
|
|
313
|
+
['A', 'B', 'C', 'A', 'D']
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
"""
|
|
317
|
+
return self.apply(mit.unique_justseen, key=key)
|
|
318
|
+
|
|
319
|
+
def unique_in_window(
|
|
320
|
+
self, n: int, key: Callable[[T], Any] | None = None
|
|
321
|
+
) -> Iter[T]:
|
|
322
|
+
"""
|
|
323
|
+
Yield the items from iterable that haven't been seen recently.
|
|
324
|
+
|
|
325
|
+
The items in iterable must be hashable.
|
|
326
|
+
Args:
|
|
327
|
+
n: Size of the lookback window.
|
|
328
|
+
key: Function to transform items before comparison. Defaults to None.
|
|
329
|
+
Example:
|
|
330
|
+
```python
|
|
331
|
+
>>> import pyochain as pc
|
|
332
|
+
>>> iterable = [0, 1, 0, 2, 3, 0]
|
|
333
|
+
>>> n = 3
|
|
334
|
+
>>> pc.Iter.from_(iterable).unique_in_window(n).into(list)
|
|
335
|
+
[0, 1, 2, 3, 0]
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
The key function, if provided, will be used to determine uniqueness:
|
|
339
|
+
```python
|
|
340
|
+
>>> pc.Iter.from_("abAcda").unique_in_window(3, key=str.lower).into(list)
|
|
341
|
+
['a', 'b', 'c', 'd', 'a']
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
"""
|
|
345
|
+
return self.apply(mit.unique_in_window, n, key=key)
|
|
346
|
+
|
|
347
|
+
def extract(self, indices: Iterable[int]) -> Iter[T]:
|
|
348
|
+
"""
|
|
349
|
+
Yield values at the specified indices.
|
|
350
|
+
|
|
351
|
+
- The iterable is consumed lazily and can be infinite.
|
|
352
|
+
- The indices are consumed immediately and must be finite.
|
|
353
|
+
- Raises IndexError if an index lies beyond the iterable.
|
|
354
|
+
- Raises ValueError for negative indices.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
indices: Iterable of indices to extract values from.
|
|
358
|
+
Example:
|
|
359
|
+
```python
|
|
360
|
+
>>> import pyochain as pc
|
|
361
|
+
>>> text = "abcdefghijklmnopqrstuvwxyz"
|
|
362
|
+
>>> pc.Iter.from_(text).extract([7, 4, 11, 11, 14]).into(list)
|
|
363
|
+
['h', 'e', 'l', 'l', 'o']
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
"""
|
|
367
|
+
return self.apply(mit.extract, indices)
|
|
368
|
+
|
|
369
|
+
def every(self, index: int) -> Iter[T]:
|
|
370
|
+
"""
|
|
371
|
+
Return every nth item starting from first.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
index: Step size for selecting items.
|
|
375
|
+
Example:
|
|
376
|
+
```python
|
|
377
|
+
>>> import pyochain as pc
|
|
378
|
+
>>> pc.Iter.from_([10, 20, 30, 40]).every(2).into(list)
|
|
379
|
+
[10, 30]
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
"""
|
|
383
|
+
return self.apply(partial(cz.itertoolz.take_nth, index))
|
|
384
|
+
|
|
385
|
+
def slice(self, start: int | None = None, stop: int | None = None) -> Iter[T]:
|
|
386
|
+
"""
|
|
387
|
+
Return a slice of the iterable.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
start: Starting index of the slice. Defaults to None.
|
|
391
|
+
stop: Ending index of the slice. Defaults to None.
|
|
392
|
+
Example:
|
|
393
|
+
```python
|
|
394
|
+
>>> import pyochain as pc
|
|
395
|
+
>>> pc.Iter.from_([1, 2, 3, 4, 5]).slice(1, 4).into(list)
|
|
396
|
+
[2, 3, 4]
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
def _slice(data: Iterable[T]) -> Iterator[T]:
|
|
402
|
+
return itertools.islice(data, start, stop)
|
|
403
|
+
|
|
404
|
+
return self.apply(_slice)
|
|
405
|
+
|
|
406
|
+
def filter_subclass[U: type[Any], R](
|
|
407
|
+
self: IterWrapper[U], parent: type[R], keep_parent: bool = True
|
|
408
|
+
) -> Iter[type[R]]:
|
|
409
|
+
"""
|
|
410
|
+
Return elements that are subclasses of the given class, optionally excluding the parent class itself.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
parent: Parent class to check against.
|
|
414
|
+
keep_parent: Whether to include the parent class itself. Defaults to True.
|
|
415
|
+
Example:
|
|
416
|
+
```python
|
|
417
|
+
>>> import pyochain as pc
|
|
418
|
+
>>> class A:
|
|
419
|
+
... pass
|
|
420
|
+
>>> class B(A):
|
|
421
|
+
... pass
|
|
422
|
+
>>> class C:
|
|
423
|
+
... pass
|
|
424
|
+
>>> def name(cls: type[Any]) -> str:
|
|
425
|
+
... return cls.__name__
|
|
426
|
+
>>>
|
|
427
|
+
>>> data = pc.Seq([A, B, C])
|
|
428
|
+
>>> data.iter().filter_subclass(A).map(name).into(list)
|
|
429
|
+
['A', 'B']
|
|
430
|
+
>>> data.iter().filter_subclass(A, keep_parent=False).map(name).into(list)
|
|
431
|
+
['B']
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
"""
|
|
435
|
+
|
|
436
|
+
def _filter_subclass(
|
|
437
|
+
data: Iterable[type[Any]],
|
|
438
|
+
) -> Generator[type[R], None, None]:
|
|
439
|
+
if keep_parent:
|
|
440
|
+
return (x for x in data if issubclass(x, parent))
|
|
441
|
+
else:
|
|
442
|
+
return (x for x in data if issubclass(x, parent) and x is not parent)
|
|
443
|
+
|
|
444
|
+
return self.apply(_filter_subclass)
|
|
445
|
+
|
|
446
|
+
def filter_type[R](self, typ: type[R]) -> Iter[R]:
|
|
447
|
+
"""
|
|
448
|
+
Return elements that are instances of the given type.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
typ: Type to check against.
|
|
452
|
+
Example:
|
|
453
|
+
```python
|
|
454
|
+
>>> import pyochain as pc
|
|
455
|
+
>>> pc.Iter.from_([1, "two", 3.0, "four", 5]).filter_type(int).into(list)
|
|
456
|
+
[1, 5]
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
"""
|
|
460
|
+
|
|
461
|
+
def _filter_type(data: Iterable[T]) -> Generator[R, None, None]:
|
|
462
|
+
return (x for x in data if isinstance(x, typ))
|
|
463
|
+
|
|
464
|
+
return self.apply(_filter_type)
|
|
465
|
+
|
|
466
|
+
def filter_callable(self) -> Iter[Callable[..., Any]]:
|
|
467
|
+
"""
|
|
468
|
+
Return only elements that are callable.
|
|
469
|
+
|
|
470
|
+
Example:
|
|
471
|
+
```python
|
|
472
|
+
>>> import pyochain as pc
|
|
473
|
+
>>> pc.Iter.from_([len, 42, str, None, list]).filter_callable().into(list)
|
|
474
|
+
[<built-in function len>, <class 'str'>, <class 'list'>]
|
|
475
|
+
|
|
476
|
+
```
|
|
477
|
+
"""
|
|
478
|
+
|
|
479
|
+
def _filter_callable(
|
|
480
|
+
data: Iterable[T],
|
|
481
|
+
) -> Generator[Callable[..., Any], None, None]:
|
|
482
|
+
return (x for x in data if callable(x))
|
|
483
|
+
|
|
484
|
+
return self.apply(_filter_callable)
|
|
485
|
+
|
|
486
|
+
def filter_map[R](self, func: Callable[[T], R]) -> Iter[R]:
|
|
487
|
+
"""
|
|
488
|
+
Apply func to every element of iterable, yielding only those which are not None.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
func: Function to apply to each item.
|
|
492
|
+
Example:
|
|
493
|
+
```python
|
|
494
|
+
>>> import pyochain as pc
|
|
495
|
+
>>> def to_int(s: str) -> int | None:
|
|
496
|
+
... return int(s) if s.isnumeric() else None
|
|
497
|
+
>>> elems = ["1", "a", "2", "b", "3"]
|
|
498
|
+
>>> pc.Iter.from_(elems).filter_map(to_int).into(list)
|
|
499
|
+
[1, 2, 3]
|
|
500
|
+
|
|
501
|
+
```
|
|
502
|
+
"""
|
|
503
|
+
return self.apply(partial(mit.filter_map, func))
|