absfuyu 5.1.0__py3-none-any.whl → 5.2.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 absfuyu might be problematic. Click here for more details.
- absfuyu/__init__.py +1 -1
- absfuyu/__main__.py +3 -3
- absfuyu/cli/__init__.py +1 -1
- absfuyu/cli/color.py +3 -3
- absfuyu/cli/config_group.py +2 -2
- absfuyu/cli/do_group.py +2 -2
- absfuyu/cli/game_group.py +2 -2
- absfuyu/cli/tool_group.py +2 -3
- absfuyu/config/__init__.py +1 -1
- absfuyu/core/__init__.py +1 -1
- absfuyu/core/baseclass.py +2 -2
- absfuyu/core/baseclass2.py +1 -1
- absfuyu/core/decorator.py +4 -4
- absfuyu/core/docstring.py +43 -25
- absfuyu/core/dummy_cli.py +1 -1
- absfuyu/core/dummy_func.py +4 -4
- absfuyu/dxt/__init__.py +1 -1
- absfuyu/dxt/dictext.py +5 -2
- absfuyu/dxt/dxt_support.py +1 -1
- absfuyu/dxt/intext.py +5 -2
- absfuyu/dxt/listext.py +288 -126
- absfuyu/dxt/strext.py +75 -15
- absfuyu/extra/__init__.py +1 -1
- absfuyu/extra/beautiful.py +1 -1
- absfuyu/extra/da/__init__.py +1 -1
- absfuyu/extra/da/dadf.py +43 -4
- absfuyu/extra/da/dadf_base.py +1 -1
- absfuyu/extra/da/df_func.py +1 -1
- absfuyu/extra/da/mplt.py +1 -1
- absfuyu/extra/data_analysis.py +3 -3
- absfuyu/fun/__init__.py +1 -1
- absfuyu/fun/tarot.py +1 -1
- absfuyu/game/__init__.py +1 -1
- absfuyu/game/game_stat.py +1 -1
- absfuyu/game/sudoku.py +1 -1
- absfuyu/game/tictactoe.py +2 -3
- absfuyu/game/wordle.py +1 -1
- absfuyu/general/__init__.py +1 -1
- absfuyu/general/content.py +2 -2
- absfuyu/general/human.py +1 -1
- absfuyu/general/shape.py +1 -1
- absfuyu/logger.py +1 -1
- absfuyu/pkg_data/__init__.py +1 -1
- absfuyu/pkg_data/deprecated.py +1 -1
- absfuyu/sort.py +1 -1
- absfuyu/tools/__init__.py +16 -13
- absfuyu/tools/checksum.py +2 -2
- absfuyu/tools/converter.py +29 -8
- absfuyu/tools/generator.py +251 -110
- absfuyu/tools/inspector.py +68 -38
- absfuyu/tools/keygen.py +1 -1
- absfuyu/tools/obfuscator.py +2 -2
- absfuyu/tools/passwordlib.py +3 -4
- absfuyu/tools/shutdownizer.py +1 -1
- absfuyu/tools/web.py +1 -1
- absfuyu/typings.py +136 -0
- absfuyu/util/__init__.py +18 -4
- absfuyu/util/api.py +36 -16
- absfuyu/util/json_method.py +43 -14
- absfuyu/util/lunar.py +1 -1
- absfuyu/util/path.py +2 -2
- absfuyu/util/performance.py +120 -5
- absfuyu/util/shorten_number.py +1 -1
- absfuyu/util/text_table.py +48 -14
- absfuyu/util/zipped.py +4 -3
- absfuyu/version.py +2 -2
- {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/METADATA +1 -1
- absfuyu-5.2.0.dist-info/RECORD +76 -0
- absfuyu/core/typings.py +0 -40
- absfuyu-5.1.0.dist-info/RECORD +0 -76
- {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/WHEEL +0 -0
- {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/dxt/listext.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Data Extension
|
|
|
3
3
|
-----------------------
|
|
4
4
|
list extension
|
|
5
5
|
|
|
6
|
-
Version: 5.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.2.0
|
|
7
|
+
Date updated: 15/03/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module Package
|
|
@@ -17,13 +17,13 @@ __all__ = ["ListExt"]
|
|
|
17
17
|
import operator
|
|
18
18
|
import random
|
|
19
19
|
from collections import Counter
|
|
20
|
-
from collections.abc import Callable
|
|
20
|
+
from collections.abc import Callable, Iterable
|
|
21
21
|
from itertools import accumulate, chain, groupby
|
|
22
|
-
from typing import Any, Self
|
|
22
|
+
from typing import Any, Literal, Self, cast, overload
|
|
23
23
|
|
|
24
|
-
from absfuyu.core import ShowAllMethodsMixin
|
|
25
|
-
from absfuyu.core.docstring import versionadded
|
|
26
|
-
from absfuyu.util import
|
|
24
|
+
from absfuyu.core.baseclass import ShowAllMethodsMixin
|
|
25
|
+
from absfuyu.core.docstring import deprecated, versionadded, versionchanged
|
|
26
|
+
from absfuyu.util import set_min_max
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
# Class
|
|
@@ -31,15 +31,20 @@ from absfuyu.util import set_min, set_min_max
|
|
|
31
31
|
class ListExt(ShowAllMethodsMixin, list):
|
|
32
32
|
"""
|
|
33
33
|
``list`` extension
|
|
34
|
+
|
|
35
|
+
>>> # For a list of new methods
|
|
36
|
+
>>> ListExt.show_all_methods()
|
|
34
37
|
"""
|
|
35
38
|
|
|
39
|
+
# Deprecated
|
|
40
|
+
@deprecated("5.2.0", reason="Use ListExt.apply(str) instead")
|
|
36
41
|
def stringify(self) -> Self:
|
|
37
42
|
"""
|
|
38
43
|
Convert all item in ``list`` into string
|
|
39
44
|
|
|
40
45
|
Returns
|
|
41
46
|
-------
|
|
42
|
-
|
|
47
|
+
Self
|
|
43
48
|
A list with all items with type <str`>
|
|
44
49
|
|
|
45
50
|
|
|
@@ -51,6 +56,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
51
56
|
"""
|
|
52
57
|
return self.__class__(map(str, self))
|
|
53
58
|
|
|
59
|
+
# Info
|
|
54
60
|
def head(self, number_of_items: int = 5) -> list:
|
|
55
61
|
"""
|
|
56
62
|
Show first ``number_of_items`` items in ``ListExt``
|
|
@@ -91,6 +97,31 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
91
97
|
)
|
|
92
98
|
return self[::-1][:number_of_items][::-1]
|
|
93
99
|
|
|
100
|
+
# Misc
|
|
101
|
+
def apply(self, func: Callable[[Any], Any]) -> Self:
|
|
102
|
+
"""
|
|
103
|
+
Apply function to each entry
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
func : Callable
|
|
108
|
+
Callable function
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
Self
|
|
113
|
+
ListExt
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
--------
|
|
118
|
+
>>> test = ListExt([1, 2, 3])
|
|
119
|
+
>>> test.apply(str)
|
|
120
|
+
['1', '2', '3']
|
|
121
|
+
"""
|
|
122
|
+
# return self.__class__(map(func, self))
|
|
123
|
+
return self.__class__(func(x) for x in self)
|
|
124
|
+
|
|
94
125
|
def sorts(self, reverse: bool = False) -> Self:
|
|
95
126
|
"""
|
|
96
127
|
Sort all items (with different type) in ``list``
|
|
@@ -98,13 +129,12 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
98
129
|
Parameters
|
|
99
130
|
----------
|
|
100
131
|
reverse : bool
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
| (Default: ``False``)
|
|
132
|
+
- ``True`` then sort in descending order
|
|
133
|
+
- ``False`` then sort in ascending order (default value)
|
|
104
134
|
|
|
105
135
|
Returns
|
|
106
136
|
-------
|
|
107
|
-
|
|
137
|
+
Self
|
|
108
138
|
A sorted list
|
|
109
139
|
|
|
110
140
|
|
|
@@ -128,6 +158,25 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
128
158
|
# logger.debug(output)
|
|
129
159
|
return self.__class__(output)
|
|
130
160
|
|
|
161
|
+
@overload
|
|
162
|
+
def freq(self) -> dict: ...
|
|
163
|
+
|
|
164
|
+
@overload
|
|
165
|
+
def freq(
|
|
166
|
+
self,
|
|
167
|
+
sort: bool = False,
|
|
168
|
+
num_of_first_char: int | None = None,
|
|
169
|
+
appear_increment: Literal[False] = ...,
|
|
170
|
+
) -> dict: ...
|
|
171
|
+
|
|
172
|
+
@overload
|
|
173
|
+
def freq(
|
|
174
|
+
self,
|
|
175
|
+
sort: bool = False,
|
|
176
|
+
num_of_first_char: int | None = None,
|
|
177
|
+
appear_increment: Literal[True] = ...,
|
|
178
|
+
) -> list[int]: ...
|
|
179
|
+
|
|
131
180
|
def freq(
|
|
132
181
|
self,
|
|
133
182
|
sort: bool = False,
|
|
@@ -139,18 +188,17 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
139
188
|
|
|
140
189
|
Parameters
|
|
141
190
|
----------
|
|
142
|
-
sort : bool
|
|
143
|
-
|
|
144
|
-
|
|
191
|
+
sort : bool, optional
|
|
192
|
+
- ``True``: Sorts the output in ascending order
|
|
193
|
+
- ``False``: No sort (default value)
|
|
145
194
|
|
|
146
|
-
num_of_first_char : int | None
|
|
147
|
-
| Number of first character taken into account to sort
|
|
148
|
-
|
|
|
149
|
-
| (num_of_first_char = ``1``: first character in each item)
|
|
195
|
+
num_of_first_char : int | None, optional
|
|
196
|
+
| Number of first character taken into account to sort, by default ``None``
|
|
197
|
+
| Eg: ``num_of_first_char = 1``: first character of each item
|
|
150
198
|
|
|
151
|
-
appear_increment : bool
|
|
152
|
-
|
|
153
|
-
|
|
199
|
+
appear_increment : bool, optional
|
|
200
|
+
Returns incremental index list of each item when sort,
|
|
201
|
+
by default ``False``
|
|
154
202
|
|
|
155
203
|
Returns
|
|
156
204
|
-------
|
|
@@ -171,7 +219,6 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
171
219
|
>>> test.freq(appear_increment=True)
|
|
172
220
|
[2, 3, 5, 6, 7, 8]
|
|
173
221
|
"""
|
|
174
|
-
|
|
175
222
|
if sort:
|
|
176
223
|
data = self.sorts().copy()
|
|
177
224
|
else:
|
|
@@ -191,7 +238,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
191
238
|
|
|
192
239
|
try:
|
|
193
240
|
times_appear = dict(sorted(temp.items()))
|
|
194
|
-
except
|
|
241
|
+
except TypeError:
|
|
195
242
|
times_appear = dict(self.__class__(temp.items()).sorts())
|
|
196
243
|
# logger.debug(times_appear)
|
|
197
244
|
|
|
@@ -204,44 +251,110 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
204
251
|
else:
|
|
205
252
|
return times_appear # character frequency
|
|
206
253
|
|
|
207
|
-
|
|
254
|
+
@versionchanged("5.2.0", reason="New ``recursive`` parameter")
|
|
255
|
+
def flatten(self, recursive: bool = False) -> Self:
|
|
208
256
|
"""
|
|
209
|
-
|
|
257
|
+
Flatten the list
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
recursive : bool
|
|
262
|
+
Recursively flatten the list, by default ``False``
|
|
263
|
+
|
|
264
|
+
Returns
|
|
265
|
+
-------
|
|
266
|
+
Self
|
|
267
|
+
Flattened list
|
|
210
268
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
269
|
+
|
|
270
|
+
Example:
|
|
271
|
+
--------
|
|
272
|
+
>>> test = ListExt([["test"], ["test", "test"], ["test"]])
|
|
273
|
+
>>> test.flatten()
|
|
274
|
+
['test', 'test', 'test', 'test']
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
def instance_checking(item):
|
|
278
|
+
if isinstance(item, str):
|
|
279
|
+
return [item]
|
|
280
|
+
if isinstance(item, Iterable):
|
|
281
|
+
return item
|
|
282
|
+
return [item]
|
|
283
|
+
|
|
284
|
+
# Flatten
|
|
285
|
+
list_of_list = (instance_checking(x) for x in self)
|
|
286
|
+
flattened = self.__class__(chain(*list_of_list))
|
|
287
|
+
|
|
288
|
+
# Recursive
|
|
289
|
+
if recursive:
|
|
290
|
+
|
|
291
|
+
def _condition(item) -> bool:
|
|
292
|
+
if isinstance(item, str):
|
|
293
|
+
return False
|
|
294
|
+
return isinstance(item, Iterable)
|
|
295
|
+
|
|
296
|
+
while any(flattened.apply(_condition)):
|
|
297
|
+
flattened = flattened.flatten()
|
|
298
|
+
|
|
299
|
+
# Return
|
|
300
|
+
return flattened
|
|
301
|
+
|
|
302
|
+
@versionadded("5.2.0")
|
|
303
|
+
def join(self, sep: str = " ", /) -> str:
|
|
304
|
+
"""
|
|
305
|
+
Join every element in list to str (``str.join()`` wrapper).
|
|
215
306
|
|
|
216
307
|
Parameters
|
|
217
308
|
----------
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
the list. These indices are *exclusive* of the starting sublist
|
|
221
|
-
but *inclusive* of the ending sublist.
|
|
309
|
+
sep : str, optional
|
|
310
|
+
Separator between each element, by default ``" "``
|
|
222
311
|
|
|
223
312
|
Returns
|
|
224
313
|
-------
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
defined by the provided split points.
|
|
314
|
+
str
|
|
315
|
+
Joined list
|
|
228
316
|
|
|
229
317
|
|
|
230
318
|
Example:
|
|
231
319
|
--------
|
|
232
|
-
>>>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
>>>
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
[[1, 1, 2, 3, 3, 4, 5, 6]]
|
|
320
|
+
>>> ListExt(["a", "b", "c"]).join()
|
|
321
|
+
a b c
|
|
322
|
+
|
|
323
|
+
>>> # Also work with non-str type
|
|
324
|
+
>>> ListExt([1, 2, 3]).join()
|
|
325
|
+
1 2 3
|
|
239
326
|
"""
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
327
|
+
try:
|
|
328
|
+
return sep.join(self)
|
|
329
|
+
except TypeError:
|
|
330
|
+
return sep.join(self.apply(str))
|
|
331
|
+
|
|
332
|
+
def numbering(self, start: int = 0) -> Self:
|
|
333
|
+
"""
|
|
334
|
+
Number the item in list
|
|
335
|
+
(``enumerate`` wrapper)
|
|
336
|
+
|
|
337
|
+
Parameters
|
|
338
|
+
----------
|
|
339
|
+
start : int
|
|
340
|
+
Start from which number, by default ``0``
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
Self
|
|
345
|
+
Counted list
|
|
244
346
|
|
|
347
|
+
|
|
348
|
+
Example:
|
|
349
|
+
--------
|
|
350
|
+
>>> test = ListExt([9, 9, 9])
|
|
351
|
+
>>> test.numbering()
|
|
352
|
+
[(0, 9), (1, 9), (2, 9)]
|
|
353
|
+
"""
|
|
354
|
+
start = max(start, 0)
|
|
355
|
+
return self.__class__(enumerate(self, start=start))
|
|
356
|
+
|
|
357
|
+
# Random
|
|
245
358
|
def pick_one(self) -> Any:
|
|
246
359
|
"""
|
|
247
360
|
Pick one random items from ``list``
|
|
@@ -273,8 +386,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
273
386
|
Parameters
|
|
274
387
|
----------
|
|
275
388
|
number_of_items : int
|
|
276
|
-
|
|
277
|
-
| (Default: ``5``)
|
|
389
|
+
Number random of items, by default ``5``
|
|
278
390
|
|
|
279
391
|
Returns
|
|
280
392
|
-------
|
|
@@ -283,13 +395,15 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
283
395
|
"""
|
|
284
396
|
return [self.pick_one() for _ in range(number_of_items)]
|
|
285
397
|
|
|
398
|
+
# Len
|
|
399
|
+
@versionchanged("5.2.0", reason="Handle more type")
|
|
286
400
|
def len_items(self) -> Self:
|
|
287
401
|
"""
|
|
288
|
-
``len()`` for every item in ``
|
|
402
|
+
``len()`` for every item in ``self``
|
|
289
403
|
|
|
290
404
|
Returns
|
|
291
405
|
-------
|
|
292
|
-
|
|
406
|
+
Self
|
|
293
407
|
List of ``len()``'ed value
|
|
294
408
|
|
|
295
409
|
|
|
@@ -299,14 +413,24 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
299
413
|
>>> test.len_items()
|
|
300
414
|
[3, 3, 5]
|
|
301
415
|
"""
|
|
302
|
-
out = self.__class__([len(str(x)) for x in self])
|
|
303
|
-
# out = ListExt(map(lambda x: len(str(x)), self))
|
|
304
|
-
# logger.debug(out)
|
|
305
|
-
return out
|
|
306
416
|
|
|
307
|
-
|
|
417
|
+
def _len(item: Any) -> int:
|
|
418
|
+
try:
|
|
419
|
+
return len(item)
|
|
420
|
+
except TypeError:
|
|
421
|
+
return len(str(item))
|
|
422
|
+
|
|
423
|
+
return self.__class__([_len(x) for x in self])
|
|
424
|
+
|
|
425
|
+
@versionchanged("5.2.0", reason="New ``recursive`` parameter")
|
|
426
|
+
def mean_len(self, recursive: bool = False) -> float:
|
|
308
427
|
"""
|
|
309
|
-
Average length of every item
|
|
428
|
+
Average length of every item. Returns zero if failed (empty list, ZeroDivisionError).
|
|
429
|
+
|
|
430
|
+
Parameters
|
|
431
|
+
----------
|
|
432
|
+
recursive : bool
|
|
433
|
+
Recursively find the average length of items in nested lists, by default ``False``
|
|
310
434
|
|
|
311
435
|
Returns
|
|
312
436
|
-------
|
|
@@ -320,41 +444,55 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
320
444
|
>>> test.mean_len()
|
|
321
445
|
3.6666666666666665
|
|
322
446
|
"""
|
|
323
|
-
out = sum(self.len_items()) / len(self)
|
|
324
|
-
# logger.debug(out)
|
|
325
|
-
return out
|
|
326
447
|
|
|
327
|
-
|
|
448
|
+
if recursive:
|
|
449
|
+
dat = self.flatten(recursive=recursive)
|
|
450
|
+
else:
|
|
451
|
+
dat = self
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
return sum(dat.len_items()) / len(dat)
|
|
455
|
+
except ZeroDivisionError:
|
|
456
|
+
return 0.0
|
|
457
|
+
|
|
458
|
+
@versionadded("5.2.0")
|
|
459
|
+
def max_item_len(self, recursive: bool = False) -> int:
|
|
328
460
|
"""
|
|
329
|
-
|
|
461
|
+
Find the maximum length of items in the list.
|
|
330
462
|
|
|
331
463
|
Parameters
|
|
332
464
|
----------
|
|
333
|
-
|
|
334
|
-
|
|
465
|
+
recursive : bool
|
|
466
|
+
Recursively find the maximum length of items in nested lists, by default ``False``
|
|
335
467
|
|
|
336
468
|
Returns
|
|
337
469
|
-------
|
|
338
|
-
|
|
339
|
-
|
|
470
|
+
int
|
|
471
|
+
Maximum length of items
|
|
340
472
|
|
|
341
473
|
|
|
342
474
|
Example:
|
|
343
475
|
--------
|
|
344
|
-
>>> test = ListExt([
|
|
345
|
-
>>> test.
|
|
346
|
-
|
|
476
|
+
>>> test = ListExt(["test", "longer_test"])
|
|
477
|
+
>>> test.max_item_len()
|
|
478
|
+
11
|
|
479
|
+
|
|
480
|
+
>>> test = ListExt([["short"], ["longer_test"]])
|
|
481
|
+
>>> test.max_item_len(recursive=True)
|
|
482
|
+
11
|
|
347
483
|
"""
|
|
348
|
-
|
|
349
|
-
|
|
484
|
+
if recursive:
|
|
485
|
+
return cast(int, max(self.flatten(recursive=True).len_items()))
|
|
486
|
+
return cast(int, max(self.len_items()))
|
|
350
487
|
|
|
488
|
+
# Group/Unique
|
|
351
489
|
def unique(self) -> Self:
|
|
352
490
|
"""
|
|
353
491
|
Remove duplicates
|
|
354
492
|
|
|
355
493
|
Returns
|
|
356
494
|
-------
|
|
357
|
-
|
|
495
|
+
Self
|
|
358
496
|
Duplicates removed list
|
|
359
497
|
|
|
360
498
|
|
|
@@ -372,7 +510,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
372
510
|
|
|
373
511
|
Returns
|
|
374
512
|
-------
|
|
375
|
-
|
|
513
|
+
Self
|
|
376
514
|
Grouped value
|
|
377
515
|
|
|
378
516
|
|
|
@@ -424,7 +562,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
424
562
|
iter = self.copy()
|
|
425
563
|
|
|
426
564
|
# Init loop
|
|
427
|
-
for _ in range(
|
|
565
|
+
for _ in range(max(max_loop, 3)):
|
|
428
566
|
temp: dict[Any, list] = {}
|
|
429
567
|
# Make dict{key: all `item` that contains `key`}
|
|
430
568
|
for item in iter:
|
|
@@ -442,57 +580,47 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
442
580
|
|
|
443
581
|
return list(x for x, _ in groupby(iter))
|
|
444
582
|
|
|
445
|
-
|
|
583
|
+
# Slicing
|
|
584
|
+
def slice_points(self, points: list[int]) -> Self:
|
|
446
585
|
"""
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
Returns
|
|
450
|
-
-------
|
|
451
|
-
ListExt
|
|
452
|
-
Flattened list
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
Example:
|
|
456
|
-
--------
|
|
457
|
-
>>> test = ListExt([["test"], ["test", "test"], ["test"]])
|
|
458
|
-
>>> test.flatten()
|
|
459
|
-
['test', 'test', 'test', 'test']
|
|
460
|
-
"""
|
|
461
|
-
try:
|
|
462
|
-
# return self.__class__(sum(self, start=[]))
|
|
463
|
-
return self.__class__(chain(*self))
|
|
464
|
-
except Exception:
|
|
465
|
-
temp = list(map(lambda x: x if isinstance(x, list) else [x], self))
|
|
466
|
-
return self.__class__(chain(*temp))
|
|
586
|
+
Splits a list into sublists based on specified split points (indices).
|
|
467
587
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
588
|
+
This method divides the original list into multiple sublists. The ``points``
|
|
589
|
+
argument provides the indices at which the list should be split. The resulting
|
|
590
|
+
list of lists contains the sublists created by these splits. The original
|
|
591
|
+
list is not modified.
|
|
472
592
|
|
|
473
593
|
Parameters
|
|
474
594
|
----------
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
595
|
+
points : list
|
|
596
|
+
A list of integer indices representing the points at which to split
|
|
597
|
+
the list. These indices are *exclusive* of the starting sublist
|
|
598
|
+
but *inclusive* of the ending sublist.
|
|
478
599
|
|
|
479
600
|
Returns
|
|
480
601
|
-------
|
|
481
|
-
|
|
482
|
-
|
|
602
|
+
Self | list[list]
|
|
603
|
+
A list of lists, where each inner list is a slice of the original list
|
|
604
|
+
defined by the provided split points.
|
|
483
605
|
|
|
484
606
|
|
|
485
607
|
Example:
|
|
486
608
|
--------
|
|
487
|
-
>>> test = ListExt([
|
|
488
|
-
>>> test.
|
|
489
|
-
[
|
|
609
|
+
>>> test = ListExt([1, 1, 2, 3, 3, 4, 5, 6])
|
|
610
|
+
>>> test.slice_points([2, 5])
|
|
611
|
+
[[1, 1], [2, 3, 3], [4, 5, 6]]
|
|
612
|
+
>>> test.slice_points([0, 1, 2, 3, 4, 5, 6, 7, 8])
|
|
613
|
+
[[], [1], [1], [2], [3], [3], [4], [5], [6]]
|
|
614
|
+
>>> test.slice_points([])
|
|
615
|
+
[[1, 1, 2, 3, 3, 4, 5, 6]]
|
|
490
616
|
"""
|
|
491
|
-
|
|
492
|
-
|
|
617
|
+
points.append(len(self))
|
|
618
|
+
data = self.copy()
|
|
619
|
+
# return [data[points[i]:points[i+1]] for i in range(len(points)-1)]
|
|
620
|
+
return self.__class__(data[i1:i2] for i1, i2 in zip([0] + points[:-1], points))
|
|
493
621
|
|
|
494
|
-
@versionadded("5.1.0")
|
|
495
|
-
def split_chunk(self, chunk_size: int) ->
|
|
622
|
+
@versionadded("5.1.0")
|
|
623
|
+
def split_chunk(self, chunk_size: int) -> Self:
|
|
496
624
|
"""
|
|
497
625
|
Split list into smaller chunks
|
|
498
626
|
|
|
@@ -503,7 +631,7 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
503
631
|
|
|
504
632
|
Returns
|
|
505
633
|
-------
|
|
506
|
-
list[list]
|
|
634
|
+
Self | list[list]
|
|
507
635
|
List of chunk
|
|
508
636
|
|
|
509
637
|
|
|
@@ -515,19 +643,53 @@ class ListExt(ShowAllMethodsMixin, list):
|
|
|
515
643
|
slice_points = list(range(0, len(self), max(chunk_size, 1)))[1:]
|
|
516
644
|
return self.slice_points(slice_points)
|
|
517
645
|
|
|
518
|
-
@
|
|
519
|
-
|
|
520
|
-
def _group_by_unique(iterable: list) -> list[list]:
|
|
646
|
+
@versionadded("5.2.0") # no test case yet
|
|
647
|
+
def wrap_to_column(self, width: int, margin: int = 4) -> Self:
|
|
521
648
|
"""
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
return list([list(g) for _, g in groupby(iterable)])
|
|
649
|
+
Arrange list[str] items into aligned text columns (for printing)
|
|
650
|
+
with automatic column count calculation.
|
|
525
651
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
652
|
+
Parameters
|
|
653
|
+
----------
|
|
654
|
+
width : int
|
|
655
|
+
Total available display width (must be >= ``margin``)
|
|
656
|
+
|
|
657
|
+
margin : int, optional
|
|
658
|
+
Reserved space for borders/padding, by default ``4``
|
|
659
|
+
|
|
660
|
+
Returns
|
|
661
|
+
-------
|
|
662
|
+
Self
|
|
663
|
+
New instance type[list[str]] with formatted column strings.
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
Example:
|
|
667
|
+
--------
|
|
668
|
+
>>> items = ListExt(["apple", "banana", "cherry", "date"])
|
|
669
|
+
>>> print(items.wrap_to_column(30))
|
|
670
|
+
['apple banana cherry ', 'date ']
|
|
671
|
+
|
|
672
|
+
>>> items.wrap_to_column(15)
|
|
673
|
+
['apple ', 'banana ', 'cherry ', 'date ']
|
|
531
674
|
"""
|
|
532
|
-
|
|
533
|
-
|
|
675
|
+
|
|
676
|
+
max_item_length = self.max_item_len() + 1 # +1 for spacing
|
|
677
|
+
available_width = max(width, 4) - max(margin, 2) # Set boundary
|
|
678
|
+
|
|
679
|
+
# Calculate how many columns of text
|
|
680
|
+
column_count = (
|
|
681
|
+
max(1, available_width // max_item_length) if max_item_length > 0 else 1
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
# splitted_chunk: list[list[str]] = self.split_chunk(cols)
|
|
685
|
+
# mod_chunk = self.__class__(
|
|
686
|
+
# [[x.ljust(max_name_len, " ") for x in chunk] for chunk in splitted_chunk]
|
|
687
|
+
# ).apply(lambda x: "".join(x))
|
|
688
|
+
|
|
689
|
+
def mod_item(item: list[str]) -> str:
|
|
690
|
+
# Set width for str item and join them together
|
|
691
|
+
return "".join(x.ljust(max_item_length, " ") for x in item)
|
|
692
|
+
|
|
693
|
+
mod_chunk = self.split_chunk(column_count).apply(mod_item)
|
|
694
|
+
|
|
695
|
+
return mod_chunk
|