Coverage for src / toolbox_python / lists.py: 100%

14 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-02 22:56 +0000

1# ============================================================================ # 

2# # 

3# Title : Lists # 

4# Purpose : Manipulate and enhance lists. # 

5# # 

6# ============================================================================ # 

7 

8 

9# ---------------------------------------------------------------------------- # 

10# # 

11# Overview #### 

12# # 

13# ---------------------------------------------------------------------------- # 

14 

15 

16# ---------------------------------------------------------------------------- # 

17# Description #### 

18# ---------------------------------------------------------------------------- # 

19 

20 

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""" 

27 

28 

29# ---------------------------------------------------------------------------- # 

30# # 

31# Setup #### 

32# # 

33# ---------------------------------------------------------------------------- # 

34 

35 

36# ---------------------------------------------------------------------------- # 

37# Imports #### 

38# ---------------------------------------------------------------------------- # 

39 

40 

41# ## Python StdLib Imports ---- 

42from collections.abc import Collection 

43from itertools import product as itertools_product 

44from typing import Any, Optional 

45 

46# ## Python Third Party Imports ---- 

47from more_itertools import collapse as itertools_collapse 

48from typeguard import typechecked 

49 

50 

51# ---------------------------------------------------------------------------- # 

52# Exports #### 

53# ---------------------------------------------------------------------------- # 

54 

55 

56__all__: list[str] = ["flatten", "flat_list", "product"] 

57 

58 

59# ---------------------------------------------------------------------------- # 

60# # 

61# Functions #### 

62# # 

63# ---------------------------------------------------------------------------- # 

64 

65 

66@typechecked 

67def flatten( 

68 list_of_lists: Collection[Collection[Any]], 

69 base_type: Optional[type] = None, 

70 levels: Optional[int] = None, 

71) -> list[Any]: 

72 """ 

73 !!! note "Summary" 

74 For a given `#!py list` of `#!py list`'s, flatten it out to be a single `#!py list`. 

75 

76 ???+ abstract "Details" 

77 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. 

78 

79 [more_itertools]: https://more-itertools.readthedocs.io/en/stable/api.html 

80 [more_itertools.collapse]: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse 

81 

82 Params: 

83 list_of_lists (Collection[Collection[Any]]): 

84 The input `#!py list` of `#!py list`'s that you'd like to flatten to a single-level `#!py list`. 

85 base_type (Optional[type], optional): 

86 Binary and text strings are not considered iterable and will not be collapsed. To avoid collapsing other types, specify `base_type`.<br> 

87 Defaults to `#!py None`. 

88 levels (Optional[int], optional): 

89 Specify `levels` to stop flattening after a certain nested level.<br> 

90 Defaults to `#!py None`. 

91 

92 Raises: 

93 (TypeCheckError): 

94 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. 

95 

96 Returns: 

97 (any_list): 

98 The updated `#!py list`. 

99 

100 ???+ example "Examples" 

101 

102 ```pycon {.py .python linenums="1" title="Set up"} 

103 >>> from toolbox_python.lists import flatten 

104 ``` 

105 

106 ```pycon {.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> 

115 

116 ```pycon {.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> 

125 

126 ```pycon {.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> 

135 

136 ```pycon {.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> 

145 

146 ```pycon {.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> 

155 

156 ```pycon {.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> 

165 

166 ```pycon {.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> 

175 

176 ```pycon {.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> 

185 

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 ) 

197 

198 

199@typechecked 

200def flat_list(*inputs: Any) -> list[Any]: 

201 """ 

202 !!! note "Summary" 

203 Take in any number of inputs, and output them all in to a single flat `#!py list`. 

204 

205 Params: 

206 inputs (Any): 

207 Any input. 

208 

209 Raises: 

210 (TypeCheckError): 

211 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 

213 Returns: 

214 (list[Any]): 

215 The input having been coerced to a single flat `#!py list`. 

216 

217 ???+ example "Examples" 

218 

219 ```pycon {.py .python linenums="1" title="Set up"} 

220 >>> from toolbox_python.lists import flat_list 

221 ``` 

222 

223 ```pycon {.py .python linenums="1" title="Example 1: Basic input & output"} 

224 >>> print(flat_list(0, 1, 2, 3)) 

225 ``` 

226 <div class="result" markdown> 

227 ```{.sh .shell title="Terminal"} 

228 [0, 1, 2, 3] 

229 ``` 

230 !!! success "Conclusion: Successful flattening." 

231 </div> 

232 

233 ```pycon {.py .python linenums="1" title="Example 2: Multiple lists"} 

234 >>> print(flat_list([0, 1], [2, 3])) 

235 ``` 

236 <div class="result" markdown> 

237 ```{.sh .shell title="Terminal"} 

238 [0, 1, 2, 3] 

239 ``` 

240 !!! success "Conclusion: Successful flattening." 

241 </div> 

242 

243 ```pycon {.py .python linenums="1" title="Example 3: List and other data"} 

244 >>> print(flat_list(0, 1, [2, 3])) 

245 ``` 

246 <div class="result" markdown> 

247 ```{.sh .shell title="Terminal"} 

248 [0, 1, 2, 3] 

249 ``` 

250 !!! success "Conclusion: Successful flattening." 

251 </div> 

252 

253 ```pycon {.py .python linenums="1" title="Example 4: Multiple lists and other data"} 

254 >>> print(flat_list([0, 1], [2, 3], 4, 5)) 

255 ``` 

256 <div class="result" markdown> 

257 ```{.sh .shell title="Terminal"} 

258 [0, 1, 2, 3, 4, 5] 

259 ``` 

260 !!! success "Conclusion: Successful flattening." 

261 </div> 

262 

263 ```pycon {.py .python linenums="1" title="Example 5: List and a tuple and other data"} 

264 >>> print(flat_list([0, 1], (2, 3), 4, 5)) 

265 ``` 

266 <div class="result" markdown> 

267 ```{.sh .shell title="Terminal"} 

268 [0, 1, 2, 3, 4, 5] 

269 ``` 

270 !!! success "Conclusion: Successful flattening." 

271 </div> 

272 

273 ```pycon {.py .python linenums="1" title="Example 6: List and a nested list"} 

274 >>> print(flat_list([0, 1], [2, 3, [4, 5]])) 

275 ``` 

276 <div class="result" markdown> 

277 ```{.sh .shell title="Terminal"} 

278 [0, 1, 2, 3, 4, 5] 

279 ``` 

280 !!! success "Conclusion: Successful flattening." 

281 </div> 

282 

283 ```pycon {.py .python linenums="1" title="Example 7: List and a nested list and other data"} 

284 >>> print(flat_list([0, 1], [2, 3, [4, 5]], 6, 7)) 

285 ``` 

286 <div class="result" markdown> 

287 ```{.sh .shell title="Terminal"} 

288 [0, 1, 2, 3, 4, 5, 6, 7] 

289 ``` 

290 !!! success "Conclusion: Successful flattening." 

291 </div> 

292 

293 ```pycon {.py .python linenums="1" title="Example 8: Deep nested lists"} 

294 >>> print(flat_list([0, 1], [2, 3, [4, [5]]])) 

295 ``` 

296 <div class="result" markdown> 

297 ```{.sh .shell title="Terminal"} 

298 [0, 1, 2, 3, 4, 5] 

299 ``` 

300 !!! success "Conclusion: Successful flattening." 

301 </div> 

302 

303 ??? tip "See Also" 

304 - [`flatten()`][toolbox_python.lists.flatten] 

305 """ 

306 return flatten(list(inputs)) 

307 

308 

309def product(*iterables: Any) -> list[tuple[Any, ...]]: 

310 """ 

311 !!! note "Summary" 

312 For a given number of `#!py iterables`, perform a cartesian product on them, and return the result as a list. 

313 

314 ???+ abstract "Details" 

315 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 

317 [itertools]: https://docs.python.org/3/library/itertools.html 

318 [itertools.product]: https://docs.python.org/3/library/itertools.html#itertools.product 

319 

320 Params: 

321 iterables (Any): 

322 The input `#!py iterables` that you'd like to expand out. 

323 

324 Returns: 

325 (list[tuple[Any, ...]]): 

326 The updated `#!py list` list of `#!py tuple`'s representing the Cartesian product of the provided iterables. 

327 

328 ???+ example "Examples" 

329 

330 ```pycon {.py .python linenums="1" title="Set up"} 

331 >>> from toolbox_python.lists import product 

332 ``` 

333 

334 ```pycon {.py .python linenums="1" title="Example 1: Basic input & output"} 

335 >>> print(product([1], [11], [111])) 

336 ``` 

337 <div class="result" markdown> 

338 ```{.sh .shell title="Terminal"} 

339 [ 

340 (1, 11, 111), 

341 ] 

342 ``` 

343 !!! success "Conclusion: Successful conversion." 

344 </div> 

345 

346 ```pycon {.py .python linenums="1" title="Example 2: Multiple lists"} 

347 >>> print(product([1, 2], [11], [111])) 

348 ``` 

349 <div class="result" markdown> 

350 ```{.sh .shell title="Terminal"} 

351 [ 

352 (1, 11, 111), 

353 (2, 11, 111), 

354 ] 

355 ``` 

356 !!! success "Conclusion: Successful conversion." 

357 </div> 

358 

359 ```pycon {.py .python linenums="1" title="Example 3: List and other data"} 

360 >>> print(product([1, 2], [11], [111, 222])) 

361 ``` 

362 <div class="result" markdown> 

363 ```{.sh .shell title="Terminal"} 

364 [ 

365 (1, 11, 111), 

366 (1, 11, 222), 

367 (2, 11, 111), 

368 (2, 11, 222), 

369 ] 

370 ``` 

371 !!! success "Conclusion: Successful conversion." 

372 </div> 

373 

374 ```pycon {.py .python linenums="1" title="Example 4: Multiple lists and other data"} 

375 >>> print(product([1, 2], [11, 22], [111, 222])) 

376 ``` 

377 <div class="result" markdown> 

378 ```{.sh .shell title="Terminal"} 

379 [ 

380 (1, 11, 111), 

381 (1, 11, 222), 

382 (1, 22, 111), 

383 (1, 22, 222), 

384 (2, 11, 111), 

385 (2, 11, 222), 

386 (2, 22, 111), 

387 (2, 22, 222), 

388 ] 

389 ``` 

390 !!! success "Conclusion: Successful conversion." 

391 </div> 

392 

393 ??? tip "See Also" 

394 - [itertools](https://docs.python.org/3/library/itertools.html) 

395 - [itertools.product()](https://docs.python.org/3/library/itertools.html#itertools.product) 

396 """ 

397 return list(itertools_product(*iterables))