Coverage for src/toolbox_python/lists.py: 100%
14 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 10:34 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 10:34 +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 (
51 any_list,
52 any_tuple,
53 collection,
54 scalar,
55 str_list,
56)
59# ---------------------------------------------------------------------------- #
60# Exports ####
61# ---------------------------------------------------------------------------- #
63__all__: str_list = ["flatten", "flat_list", "product"]
66# ---------------------------------------------------------------------------- #
67# #
68# Functions ####
69# #
70# ---------------------------------------------------------------------------- #
73@typechecked
74def flatten(
75 list_of_lists: Union[scalar, collection],
76 base_type: Optional[type] = None,
77 levels: Optional[int] = None,
78) -> any_list:
79 """
80 !!! note "Summary"
81 For a given `#!py list` of `#!py list`'s, flatten it out to be a single `#!py list`.
83 ???+ info "Details"
84 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.
86 [more_itertools]: https://more-itertools.readthedocs.io/en/stable/api.html
87 [more_itertools.collapse]: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse
89 Params:
90 list_of_lists (list[any_list]):
91 The input `#!py list` of `#!py list`'s that you'd like to flatten to a single-level `#!py list`.
92 base_type (Optional[type], optional):
93 Binary and text strings are not considered iterable and will not be collapsed. To avoid collapsing other types, specify `base_type`.<br>
94 Defaults to `#!py None`.
95 levels (Optional[int], optional):
96 Specify `levels` to stop flattening after a certain nested level.<br>
97 Defaults to `#!py None`.
99 Raises:
100 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.
102 Returns:
103 (any_list):
104 The updated `#!py list`.
106 ???+ example "Examples"
108 ```{.py .python linenums="1" title="Set up"}
109 >>> from toolbox_python.lists import flatten
110 ```
112 ```{.py .python linenums="1" title="Example 1: Basic list, same input & output"}
113 >>> print(flatten([0, 1, 2, 3]))
114 ```
115 <div class="result" markdown>
116 ```{.sh .shell title="Terminal"}
117 [0, 1, 2, 3]
118 ```
119 !!! success "Conclusion: Successful flattening."
120 </div>
122 ```{.py .python linenums="1" title="Example 2: List containing two lists"}
123 >>> print(flatten([[0, 1], [2, 3]]))
124 ```
125 <div class="result" markdown>
126 ```{.sh .shell title="Terminal"}
127 [0, 1, 2, 3]
128 ```
129 !!! success "Conclusion: Successful flattening."
130 </div>
132 ```{.py .python linenums="1" title="Example 3: List containing a list and other data"}
133 >>> print(flatten([0, 1, [2, 3]]))
134 ```
135 <div class="result" markdown>
136 ```{.sh .shell title="Terminal"}
137 [0, 1, 2, 3]
138 ```
139 !!! success "Conclusion: Successful flattening."
140 </div>
142 ```{.py .python linenums="1" title="Example 4: List containing two lists and other data"}
143 >>> print(flatten([[0, 1], [2, 3], 4, 5]))
144 ```
145 <div class="result" markdown>
146 ```{.sh .shell title="Terminal"}
147 [0, 1, 2, 3, 4, 5]
148 ```
149 !!! success "Conclusion: Successful flattening."
150 </div>
152 ```{.py .python linenums="1" title="Example 5: List containing a list, a tuple, and other data"}
153 >>> print(flatten([[0, 1], (2, 3), 4, 5]))
154 ```
155 <div class="result" markdown>
156 ```{.sh .shell title="Terminal"}
157 [0, 1, 2, 3, 4, 5]
158 ```
159 !!! success "Conclusion: Successful flattening."
160 </div>
162 ```{.py .python linenums="1" title="Example 6: List containing up to three levels deep"}
163 >>> print(flatten([[0, 1], [2, 3, [4, 5]]]))
164 ```
165 <div class="result" markdown>
166 ```{.sh .shell title="Terminal"}
167 [0, 1, 2, 3, 4, 5]
168 ```
169 !!! success "Conclusion: Successful flattening."
170 </div>
172 ```{.py .python linenums="1" title="Example 7: List containing up to three levels deep, plus other data"}
173 >>> print(flatten([[0, 1], [2, 3, [4, 5]], 6, 7]))
174 ```
175 <div class="result" markdown>
176 ```{.sh .shell title="Terminal"}
177 [0, 1, 2, 3, 4, 5, 6, 7]
178 ```
179 !!! success "Conclusion: Successful flattening."
180 </div>
182 ```{.py .python linenums="1" title="Example 8: List containing up to four levels deep"}
183 >>> print(flatten([[0, 1], [2, 3, [4, [5]]]]))
184 ```
185 <div class="result" markdown>
186 ```{.sh .shell title="Terminal"}
187 [0, 1, 2, 3, 4, 5]
188 ```
189 !!! success "Conclusion: Successful flattening."
190 </div>
192 ??? tip "See Also"
193 - [`more_itertools`](https://more-itertools.readthedocs.io/en/stable/api.html)
194 - [`more_itertools.collapse()`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse)
195 """
196 return list(
197 itertools_collapse(
198 iterable=list_of_lists, # type: ignore
199 base_type=base_type,
200 levels=levels,
201 )
202 )
205@typechecked
206def flat_list(*inputs: Any) -> any_list:
207 """
208 !!! note "Summary"
209 Take in any number of inputs, and output them all in to a single flat `#!py list`.
211 Params:
212 inputs (Any):
213 Any input.
215 Raises:
216 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.
218 Returns:
219 (any_list):
220 The input having been coerced to a single flat `#!py list`.
222 ???+ example "Examples"
224 ```{.py .python linenums="1" title="Set up"}
225 >>> from toolbox_python.lists import flat_list
226 ```
228 ```{.py .python linenums="1" title="Example 1: Basic input & output"}
229 >>> print(flat_list(0, 1, 2, 3))
230 ```
231 <div class="result" markdown>
232 ```{.sh .shell title="Terminal"}
233 [0, 1, 2, 3]
234 ```
235 !!! success "Conclusion: Successful flattening."
236 </div>
238 ```{.py .python linenums="1" title="Example 2: Multiple lists"}
239 >>> print(flat_list([0, 1], [2, 3]))
240 ```
241 <div class="result" markdown>
242 ```{.sh .shell title="Terminal"}
243 [0, 1, 2, 3]
244 ```
245 !!! success "Conclusion: Successful flattening."
246 </div>
248 ```{.py .python linenums="1" title="Example 3: List and other data"}
249 >>> print(flat_list(0, 1, [2, 3]))
250 ```
251 <div class="result" markdown>
252 ```{.sh .shell title="Terminal"}
253 [0, 1, 2, 3]
254 ```
255 !!! success "Conclusion: Successful flattening."
256 </div>
258 ```{.py .python linenums="1" title="Example 4: Multiple lists and other data"}
259 >>> print(flat_list([0, 1], [2, 3], 4, 5))
260 ```
261 <div class="result" markdown>
262 ```{.sh .shell title="Terminal"}
263 [0, 1, 2, 3, 4, 5]
264 ```
265 !!! success "Conclusion: Successful flattening."
266 </div>
268 ```{.py .python linenums="1" title="Example 5: List and a tuple and other data"}
269 >>> print(flat_list([0, 1], (2, 3), 4, 5))
270 ```
271 <div class="result" markdown>
272 ```{.sh .shell title="Terminal"}
273 [0, 1, 2, 3, 4, 5]
274 ```
275 !!! success "Conclusion: Successful flattening."
276 </div>
278 ```{.py .python linenums="1" title="Example 6: List and a nested list"}
279 >>> print(flat_list([0, 1], [2, 3, [4, 5]]))
280 ```
281 <div class="result" markdown>
282 ```{.sh .shell title="Terminal"}
283 [0, 1, 2, 3, 4, 5]
284 ```
285 !!! success "Conclusion: Successful flattening."
286 </div>
288 ```{.py .python linenums="1" title="Example 7: List and a nested list and other data"}
289 >>> print(flat_list([0, 1], [2, 3, [4, 5]], 6, 7))
290 ```
291 <div class="result" markdown>
292 ```{.sh .shell title="Terminal"}
293 [0, 1, 2, 3, 4, 5, 6, 7]
294 ```
295 !!! success "Conclusion: Successful flattening."
296 </div>
298 ```{.py .python linenums="1" title="Example 8: Deep nested lists"}
299 >>> print(flat_list([0, 1], [2, 3, [4, [5]]]))
300 ```
301 <div class="result" markdown>
302 ```{.sh .shell title="Terminal"}
303 [0, 1, 2, 3, 4, 5]
304 ```
305 !!! success "Conclusion: Successful flattening."
306 </div>
308 ??? tip "See Also"
309 - [`flatten()`][toolbox_python.lists.flatten]
310 """
311 return flatten(list(inputs))
314def product(*iterables) -> list[any_tuple]:
315 """
316 !!! note "Summary"
317 For a given number of `#!py iterables`, perform a cartesian product on them, and return the result as a list.
319 ???+ info "Details"
320 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.
322 [itertools]: https://docs.python.org/3/library/itertools.html
323 [itertools.product]: https://docs.python.org/3/library/itertools.html#itertools.product
325 Params:
326 iterables (Any):
327 The input `#!py iterables` that you'd like to expand out.
329 Returns:
330 (list[tuple[Any, ...]]):
331 The updated `#!py list` list of `#!py tuple`'s representing the Cartesian product of the provided iterables.
333 ???+ example "Examples"
335 ```{.py .python linenums="1" title="Set up"}
336 >>> from toolbox_python.lists import product
337 ```
339 ```{.py .python linenums="1" title="Example 1: Basic input & output"}
340 >>> print(product([1], [11], [111]))
341 ```
342 <div class="result" markdown>
343 ```{.sh .shell title="Terminal"}
344 [
345 (1, 11, 111),
346 ]
347 ```
348 !!! success "Conclusion: Successful conversion."
349 </div>
351 ```{.py .python linenums="1" title="Example 2: Multiple lists"}
352 >>> print(product([1, 2], [11], [111]))
353 ```
354 <div class="result" markdown>
355 ```{.sh .shell title="Terminal"}
356 [
357 (1, 11, 111),
358 (2, 11, 111),
359 ]
360 ```
361 !!! success "Conclusion: Successful conversion."
362 </div>
364 ```{.py .python linenums="1" title="Example 3: List and other data"}
365 >>> print(product([1, 2], [11], [111, 222]))
366 ```
367 <div class="result" markdown>
368 ```{.sh .shell title="Terminal"}
369 [
370 (1, 11, 111),
371 (1, 11, 222),
372 (2, 11, 111),
373 (2, 11, 222),
374 ]
375 ```
376 !!! success "Conclusion: Successful conversion."
377 </div>
379 ```{.py .python linenums="1" title="Example 4: Multiple lists and other data"}
380 >>> print(product([1, 2], [11, 22], [111, 222]))
381 ```
382 <div class="result" markdown>
383 ```{.sh .shell title="Terminal"}
384 [
385 (1, 11, 111),
386 (1, 11, 222),
387 (1, 22, 111),
388 (1, 22, 222),
389 (2, 11, 111),
390 (2, 11, 222),
391 (2, 22, 111),
392 (2, 22, 222),
393 ]
394 ```
395 !!! success "Conclusion: Successful conversion."
396 </div>
398 ??? tip "See Also"
399 - [itertools](https://docs.python.org/3/library/itertools.html)
400 - [itertools.product()](https://docs.python.org/3/library/itertools.html#itertools.product)
401 """
402 return list(itertools_product(*iterables))