Repository navigation
Expand file tree
/
Copy pathiterator.py
More file actions
231 lines (177 loc) · 7.71 KB
/
Copy pathiterator.py
File metadata and controls
231 lines (177 loc) · 7.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/usr/bin/python
####
# Example usage of iterators with a nested object list.
####
# ref: https://docs.python.org/3/library/itertools.html
# @since: 2026-02-13
# @author: stev leibelt <artodeto@bazzline.net>
####
from collections.abc import Iterable, Iterator
class Task:
def __init__(self, name: str):
self.name = name
class TaskIterator(Iterator):
def __init__(self, nested_task_list: list[list[Task]]):
self._nested_task_list_length: int = len(nested_task_list)
self._nested_index_to_task_list_length: dict[int, int] = {}
self._nested_task_list = nested_task_list
self._next_nested_index: int = 0
self._next_task_index: int = 0
self._task_index_map: dict[Task, set(int, int)] = {}
for i, task_list in enumerate(self._nested_task_list):
self._nested_index_to_task_list_length[i] = len(task_list)
for j, task in enumerate(task_list):
if task in self._task_index_map:
raise ValueError(f"Can not add {task.name=} twice")
self._task_index_map[task] = (i, j)
def __iter__(self):
return self
def set_next_index(self, task: Task) -> None:
if not task in self._task_index_map:
raise ValueError(f"{task.name} not in collection")
nested_index, task_index = self._task_index_map[task]
self._next_task_index = nested_index + 1
self._next_task_index = task_index + 1
def __next__(self) -> list[Task]:
print(f"__next__: {self._next_nested_index=}")
print(f"__next__: {self._next_task_index=}")
if self._next_nested_index not in self._nested_index_to_task_list_length:
raise StopIteration()
print(f"__next__: {self._nested_index_to_task_list_length[self._next_nested_index]=}")
if self._next_task_index >= self._nested_index_to_task_list_length[self._next_nested_index]:
print("__next__: Jumping to next nested list")
self._next_nested_index += 1
self._next_task_index = 0
print(f"__next__: {self._next_nested_index=}")
print(f"__next__: {self._next_task_index=}")
if self._next_nested_index >= self._nested_task_list_length:
print("__next__: StopIteration")
raise StopIteration()
task_index = self._next_task_index
self._next_task_index += 1
print(f"__next__: {self._next_task_index=}")
print(f"__next__: {self._nested_task_list[self._next_nested_index][task_index].name=}")
return self._nested_task_list[self._next_nested_index][task_index]
class TaskListIterator(Iterator):
def __init__(self, nested_task_list: list[list[Task]]):
self._length: int = len(nested_task_list)
self._nested_task_list = nested_task_list
self._next_index: int = 0
self._task_index_map: dict[Task, set(int, int)] = {}
for nested_list_index, task_list in enumerate(self._nested_task_list):
for task_list_index, task in enumerate(task_list):
self._task_index_map[task] = (nested_list_index, task_list_index)
def __iter__(self):
return self
def set_next_index(self, task_list: list[Task]) -> None:
if not task_list:
raise ValueError("Task list can not be empty")
nested_index: int | None = None
for task in task_list:
if nested_index is None:
if not task in self._task_index_map:
raise ValueError("Task list not in collection")
nested_index = self._task_index_map[task][0]
if nested_index != self._task_index_map[task][0]:
raise ValueError("Task list not in collection")
if nested_index is None:
raise ValueError("Task list not in collection")
self._next_index = nested_index + 1
def __next__(self) -> list[Task]:
if self._next_index >= self._length:
raise StopIteration()
index = self._next_index
self._next_index += 1
return self._nested_task_list[index]
class TaskCollection(Iterable):
def __init__(self):
self._name_to_index_dict = {}
self._data_list: list[list[Task]] = []
self._task_index_map: dict[Task, set(int, int)] = {}
def add(self, task_list: list[Task]) -> None:
combined_name: str = '_'.join(task.name for task in task_list)
if combined_name not in self._name_to_index_dict:
self._name_to_index_dict[combined_name] = len(self._data_list)
self._data_list.append(task_list)
def __iter__(self) -> TaskListIterator:
return TaskListIterator(self._data_list)
def __contains__(self, task_list: list[Task]) -> bool:
name_to_index: str = '_'.join(task.name for task in task_list)
return name_to_index in self._name_to_index_dict
def main() -> None:
# Define some object lists
task_one_one = Task(name="task_one_one")
task_one_two = Task(name="task_one_two")
task_two_one = Task(name="task_two_one")
task_two_two = Task(name="task_two_two")
task_two_three = Task(name="task_two_three")
task_three_one = Task(name="task_three_one")
task_list_one: list[Task] = [
task_one_one,
task_one_two
]
task_list_two: list[Task] = [
task_two_one,
task_two_two,
task_two_three,
]
task_list_three: list[Task] = [
task_three_one
]
print(f"task_list_one: {', '.join(task.name for task in task_list_one)}")
print(f"task_list_two: {', '.join(task.name for task in task_list_two)}")
print(f"task_list_three: {', '.join(task.name for task in task_list_three)}")
print("")
# Create collection
collection = TaskCollection()
print(f"Adding to collection: {', '.join(task.name for task in task_list_one)}")
collection.add(task_list = task_list_one)
print(f"Adding to collection: {', '.join(task.name for task in task_list_two)}")
collection.add(task_list = task_list_two)
print("")
# Demonstrate __contains__ implementation
print(f"{task_list_one in collection=}")
print(f"{task_list_two in collection=}")
print(f"{task_list_three in collection=}")
print("")
# Demonstrate iteration
iterator = iter(collection)
# Using iterator
print("Using the TaskListIterator")
print("Iteration from the beginning")
for task_list in iterator:
print(f" task_list: {', '.join(task.name for task in task_list)}")
print("")
print("Iteration from index of task_list_two")
iterator.set_next_index(task_list=task_list_two)
for task_list in iterator:
print(f" task_list: {', '.join(task.name for task in task_list)}")
print("")
print("Iteration from index of task_list_one")
iterator.set_next_index(task_list=task_list_one)
for task_list in iterator:
print(f" task_list: {', '.join(task.name for task in task_list)}")
print("")
try:
print("Iteration from index of task_list_three")
iterator.set_next_index(task_list=task_list_three)
for task_list in iterator:
print(f" task_list: {', '.join(task.name for task in task_list)}")
print("")
except ValueError as value_error:
print(f" Expected error: {type(value_error)}: {value_error}")
print("")
print("Using the TaskIterator")
print("Iteration from the beginning")
iterator = TaskIterator(nested_task_list=collection._data_list)
for task in iterator:
print(f"{task.name=}")
print("")
print("Using the TaskIterator")
print("Iteration from index of task_two_two")
iterator.set_next_index(task_two_two)
for task in iterator:
print(f"{task.name=}")
print("")
if __name__ == '__main__':
main()