Coverage for src/toolbox_python/lists.py: 100%
14 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-13 07:24 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-13 07:24 +0000
1# ============================================================================ #
2# #
3# Title : Lists #
4# Purpose : Manipulate and enhance lists. #
5# #
6# ============================================================================ #
9# ---------------------------------------------------------------------------- #
10# #
11# Overview ####
12# #
13# ---------------------------------------------------------------------------- #
16# ---------------------------------------------------------------------------- #
17# Description ####
18# ---------------------------------------------------------------------------- #
21"""
22!!! note "Summary"
23 The `lists` module is used to manipulate and enhance Python `#!py list`'s.
24!!! abstract "Details"
25 Note that functions in this module will only take-in and manipulate existing `#!py list` objects, and also output `#!py list` objects. It will not sub-class the base `#!py list` object, or create new '`#!py list`-like' objects. It will always maintain pure python types at it's core.
26"""
29# ---------------------------------------------------------------------------- #
30# #
31# Setup ####
32# #
33# ---------------------------------------------------------------------------- #
36# ---------------------------------------------------------------------------- #
37# Imports ####
38# ---------------------------------------------------------------------------- #
41# ## Python StdLib Imports ----
42from itertools import product as itertools_product
43from typing import Any, Optional, Union
45# ## Python Third Party Imports ----
46from more_itertools import collapse as itertools_collapse
47from typeguard import typechecked
49# ## Local First Party Imports ----
50from toolbox_python.collection_types import any_list, any_tuple, collection, scalar
53# ---------------------------------------------------------------------------- #
54# Exports ####
55# ---------------------------------------------------------------------------- #
57__all__: list[str] = ["flatten", "flat_list", "product"]
60# ---------------------------------------------------------------------------- #
61# #
62# Functions ####
63# #
64# ---------------------------------------------------------------------------- #
67@typechecked
68def flatten(
69 list_of_lists: Union[scalar, collection],
70 base_type: Optional[type] = None,
71 levels: Optional[int] = None,
72) -> any_list:
73 """
74 !!! note "Summary"
75 For a given `#!py list` of `#!py list`'s, flatten it out to be a single `#!py list`.
77 ???+ info "Details"
78 Under the hood, this function will call the [`#!py more_itertools.collapse()`][more_itertools.collapse] function. The difference between this function and the [`#!py more_itertools.collapse()`][more_itertools.collapse] function is that the one from [`#!py more_itertools`][more_itertools] will return a `chain` object, not a `list` object. So, all we do here is call the [`#!py more_itertools.collapse()`][more_itertools.collapse] function, then parse the result in to a `#!py list()` function to ensure that the result is always a `#!py list` object.
80 [more_itertools]: https://more-itertools.readthedocs.io/en/stable/api.html
81 [more_itertools.collapse]: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse
83 Params:
84 list_of_lists (list[any_list]):
85 The input `#!py list` of `#!py list`'s that you'd like to flatten to a single-level `#!py list`.
86 base_type (Optional[type], optional):
87 Binary and text strings are not considered iterable and will not be collapsed. To avoid collapsing other types, specify `base_type`.<br>
88 Defaults to `#!py None`.
89 levels (Optional[int], optional):
90 Specify `levels` to stop flattening after a certain nested level.<br>
91 Defaults to `#!py None`.
93 Raises:
94 TypeError: If any of the inputs parsed to the parameters of this function are not the correct type. Uses the [`@typeguard.typechecked`](https://typeguard.readthedocs.io/en/stable/api.html#typeguard.typechecked) decorator.
96 Returns:
97 (any_list):
98 The updated `#!py list`.
100 ???+ example "Examples"
102 ```{.py .python linenums="1" title="Set up"}
103 >>> from toolbox_python.lists import flatten
104 ```
106 ```{.py .python linenums="1" title="Example 1: Basic list, same input & output"}
107 >>> print(flatten([0, 1, 2, 3]))
108 ```
109 <div class="result" markdown>
110 ```{.sh .shell title="Terminal"}
111 [0, 1, 2, 3]
112 ```
113 !!! success "Conclusion: Successful flattening."
114 </div>
116 ```{.py .python linenums="1" title="Example 2: List containing two lists"}
117 >>> print(flatten([[0, 1], [2, 3]]))
118 ```
119 <div class="result" markdown>
120 ```{.sh .shell title="Terminal"}
121 [0, 1, 2, 3]
122 ```
123 !!! success "Conclusion: Successful flattening."
124 </div>
126 ```{.py .python linenums="1" title="Example 3: List containing a list and other data"}
127 >>> print(flatten([0, 1, [2, 3]]))
128 ```
129 <div class="result" markdown>
130 ```{.sh .shell title="Terminal"}
131 [0, 1, 2, 3]
132 ```
133 !!! success "Conclusion: Successful flattening."
134 </div>
136 ```{.py .python linenums="1" title="Example 4: List containing two lists and other data"}
137 >>> print(flatten([[0, 1], [2, 3], 4, 5]))
138 ```
139 <div class="result" markdown>
140 ```{.sh .shell title="Terminal"}
141 [0, 1, 2, 3, 4, 5]
142 ```
143 !!! success "Conclusion: Successful flattening."
144 </div>
146 ```{.py .python linenums="1" title="Example 5: List containing a list, a tuple, and other data"}
147 >>> print(flatten([[0, 1], (2, 3), 4, 5]))
148 ```
149 <div class="result" markdown>
150 ```{.sh .shell title="Terminal"}
151 [0, 1, 2, 3, 4, 5]
152 ```
153 !!! success "Conclusion: Successful flattening."
154 </div>
156 ```{.py .python linenums="1" title="Example 6: List containing up to three levels deep"}
157 >>> print(flatten([[0, 1], [2, 3, [4, 5]]]))
158 ```
159 <div class="result" markdown>
160 ```{.sh .shell title="Terminal"}
161 [0, 1, 2, 3, 4, 5]
162 ```
163 !!! success "Conclusion: Successful flattening."
164 </div>
166 ```{.py .python linenums="1" title="Example 7: List containing up to three levels deep, plus other data"}
167 >>> print(flatten([[0, 1], [2, 3, [4, 5]], 6, 7]))
168 ```
169 <div class="result" markdown>
170 ```{.sh .shell title="Terminal"}
171 [0, 1, 2, 3, 4, 5, 6, 7]
172 ```
173 !!! success "Conclusion: Successful flattening."
174 </div>
176 ```{.py .python linenums="1" title="Example 8: List containing up to four levels deep"}
177 >>> print(flatten([[0, 1], [2, 3, [4, [5]]]]))
178 ```
179 <div class="result" markdown>
180 ```{.sh .shell title="Terminal"}
181 [0, 1, 2, 3, 4, 5]
182 ```
183 !!! success "Conclusion: Successful flattening."
184 </div>
186 ??? tip "See Also"
187 - [`more_itertools`](https://more-itertools.readthedocs.io/en/stable/api.html)
188 - [`more_itertools.collapse()`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse)
189 """
190 return list(
191 itertools_collapse(
192 iterable=list_of_lists,
193 base_type=base_type,
194 levels=levels,
195 )
196 )
199@typechecked
200def flat_list(*inputs: Any) -> any_list:
201 """
202 !!! note "Summary"
203 Take in any number of inputs, and output them all in to a single flat `#!py list`.
205 Params:
206 inputs (Any):
207 Any input.
209 Raises:
210 TypeError: If any of the inputs parsed to the parameters of this function are not the correct type. Uses the [`@typeguard.typechecked`](https://typeguard.readthedocs.io/en/stable/api.html#typeguard.typechecked) decorator.
212 Returns:
213 (any_list):
214 The input having been coerced to a single flat `#!py list`.
216 ???+ example "Examples"
218 ```{.py .python linenums="1" title="Set up"}
219 >>> from toolbox_python.lists import flat_list
220 ```
222 ```{.py .python linenums="1" title="Example 1: Basic input & output"}
223 >>> print(flat_list(0, 1, 2, 3))
224 ```
225 <div class="result" markdown>
226 ```{.sh .shell title="Terminal"}
227 [0, 1, 2, 3]
228 ```
229 !!! success "Conclusion: Successful flattening."
230 </div>
232 ```{.py .python linenums="1" title="Example 2: Multiple lists"}
233 >>> print(flat_list([0, 1], [2, 3]))
234 ```
235 <div class="result" markdown>
236 ```{.sh .shell title="Terminal"}
237 [0, 1, 2, 3]
238 ```
239 !!! success "Conclusion: Successful flattening."
240 </div>
242 ```{.py .python linenums="1" title="Example 3: List and other data"}
243 >>> print(flat_list(0, 1, [2, 3]))
244 ```
245 <div class="result" markdown>
246 ```{.sh .shell title="Terminal"}
247 [0, 1, 2, 3]
248 ```
249 !!! success "Conclusion: Successful flattening."
250 </div>
252 ```{.py .python linenums="1" title="Example 4: Multiple lists and other data"}
253 >>> print(flat_list([0, 1], [2, 3], 4, 5))
254 ```
255 <div class="result" markdown>
256 ```{.sh .shell title="Terminal"}
257 [0, 1, 2, 3, 4, 5]
258 ```
259 !!! success "Conclusion: Successful flattening."
260 </div>
262 ```{.py .python linenums="1" title="Example 5: List and a tuple and other data"}
263 >>> print(flat_list([0, 1], (2, 3), 4, 5))
264 ```
265 <div class="result" markdown>
266 ```{.sh .shell title="Terminal"}
267 [0, 1, 2, 3, 4, 5]
268 ```
269 !!! success "Conclusion: Successful flattening."
270 </div>
272 ```{.py .python linenums="1" title="Example 6: List and a nested list"}
273 >>> print(flat_list([0, 1], [2, 3, [4, 5]]))
274 ```
275 <div class="result" markdown>
276 ```{.sh .shell title="Terminal"}
277 [0, 1, 2, 3, 4, 5]
278 ```
279 !!! success "Conclusion: Successful flattening."
280 </div>
282 ```{.py .python linenums="1" title="Example 7: List and a nested list and other data"}
283 >>> print(flat_list([0, 1], [2, 3, [4, 5]], 6, 7))
284 ```
285 <div class="result" markdown>
286 ```{.sh .shell title="Terminal"}
287 [0, 1, 2, 3, 4, 5, 6, 7]
288 ```
289 !!! success "Conclusion: Successful flattening."
290 </div>
292 ```{.py .python linenums="1" title="Example 8: Deep nested lists"}
293 >>> print(flat_list([0, 1], [2, 3, [4, [5]]]))
294 ```
295 <div class="result" markdown>
296 ```{.sh .shell title="Terminal"}
297 [0, 1, 2, 3, 4, 5]
298 ```
299 !!! success "Conclusion: Successful flattening."
300 </div>
302 ??? tip "See Also"
303 - [`flatten()`][toolbox_python.lists.flatten]
304 """
305 return flatten(list(inputs))
308def product(*iterables) -> list[any_tuple]:
309 """
310 !!! note "Summary"
311 For a given number of `#!py iterables`, perform a cartesian product on them, and return the result as a list.
313 ???+ info "Details"
314 Under the hood, this function will call the [`#!py itertools.product()`][itertools.product] function. The difference between this function and the [`#!py itertools.product()`][itertools.product] function is that the one from [`#!py itertools`][itertools] will return a `product` object, not a `list` object. So, all we do here is call the [`#!py itertools.product()`][itertools.product] function, then parse the result in to a `#!py list()` function to ensure that the result is always a `#!py list` object.
316 [itertools]: https://docs.python.org/3/library/itertools.html
317 [itertools.product]: https://docs.python.org/3/library/itertools.html#itertools.product
319 Params:
320 iterables (Any):
321 The input `#!py iterables` that you'd like to expand out.
323 Returns:
324 (list[tuple[Any, ...]]):
325 The updated `#!py list` list of `#!py tuple`'s representing the Cartesian product of the provided iterables.
327 ???+ example "Examples"
329 ```{.py .python linenums="1" title="Set up"}
330 >>> from toolbox_python.lists import product
331 ```
333 ```{.py .python linenums="1" title="Example 1: Basic input & output"}
334 >>> print(product([1], [11], [111]))
335 ```
336 <div class="result" markdown>
337 ```{.sh .shell title="Terminal"}
338 [
339 (1, 11, 111),
340 ]
341 ```
342 !!! success "Conclusion: Successful conversion."
343 </div>
345 ```{.py .python linenums="1" title="Example 2: Multiple lists"}
346 >>> print(product([1, 2], [11], [111]))
347 ```
348 <div class="result" markdown>
349 ```{.sh .shell title="Terminal"}
350 [
351 (1, 11, 111),
352 (2, 11, 111),
353 ]
354 ```
355 !!! success "Conclusion: Successful conversion."
356 </div>
358 ```{.py .python linenums="1" title="Example 3: List and other data"}
359 >>> print(product([1, 2], [11], [111, 222]))
360 ```
361 <div class="result" markdown>
362 ```{.sh .shell title="Terminal"}
363 [
364 (1, 11, 111),
365 (1, 11, 222),
366 (2, 11, 111),
367 (2, 11, 222),
368 ]
369 ```
370 !!! success "Conclusion: Successful conversion."
371 </div>
373 ```{.py .python linenums="1" title="Example 4: Multiple lists and other data"}
374 >>> print(product([1, 2], [11, 22], [111, 222]))
375 ```
376 <div class="result" markdown>
377 ```{.sh .shell title="Terminal"}
378 [
379 (1, 11, 111),
380 (1, 11, 222),
381 (1, 22, 111),
382 (1, 22, 222),
383 (2, 11, 111),
384 (2, 11, 222),
385 (2, 22, 111),
386 (2, 22, 222),
387 ]
388 ```
389 !!! success "Conclusion: Successful conversion."
390 </div>
392 ??? tip "See Also"
393 - [itertools](https://docs.python.org/3/library/itertools.html)
394 - [itertools.product()](https://docs.python.org/3/library/itertools.html#itertools.product)
395 """
396 return list(itertools_product(*iterables))