core-data-structures 1.2.0__tar.gz → 1.2.1__tar.gz

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.
Files changed (22) hide show
  1. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/PKG-INFO +7 -2
  2. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/README.rst +4 -0
  3. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/core_data_structures.egg-info/PKG-INFO +7 -2
  4. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/core_data_structures.egg-info/SOURCES.txt +3 -0
  5. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/core_data_structures.egg-info/requires.txt +2 -1
  6. core_data_structures-1.2.1/data_structures/base.py +37 -0
  7. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/graphs/graphs.py +0 -0
  8. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/graphs/vertex.py +1 -1
  9. core_data_structures-1.2.1/data_structures/lists/singly_linked_list.py +308 -0
  10. core_data_structures-1.2.1/data_structures/py.typed +0 -0
  11. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/trees/binary_tree.py +0 -0
  12. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/pyproject.toml +3 -2
  13. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/LICENSE +0 -0
  14. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/core_data_structures.egg-info/dependency_links.txt +0 -0
  15. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/core_data_structures.egg-info/top_level.txt +0 -0
  16. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/__init__.py +0 -0
  17. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/graphs/__init__.py +0 -0
  18. /core_data_structures-1.2.0/data_structures/py.typed → /core_data_structures-1.2.1/data_structures/lists/__init__.py +0 -0
  19. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/trees/__init__.py +0 -0
  20. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/data_structures/trees/simple_tree.py +0 -0
  21. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/setup.cfg +0 -0
  22. {core_data_structures-1.2.0 → core_data_structures-1.2.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-data-structures
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: This project/library contains commons data structures...
5
5
  Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
6
6
  Maintainer: Alejandro Cora González
@@ -25,9 +25,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
25
  Requires-Python: >=3.9
26
26
  Description-Content-Type: text/x-rst
27
27
  License-File: LICENSE
28
+ Requires-Dist: core-mixins>=3.2.0
28
29
  Requires-Dist: typing-extensions>=4.8.0
29
30
  Provides-Extra: dev
30
- Requires-Dist: core-dev-tools>=2.0.0; extra == "dev"
31
+ Requires-Dist: core-dev-tools>=2.1.0; extra == "dev"
31
32
  Requires-Dist: core-tests>=2.1.0; extra == "dev"
32
33
  Dynamic: license-file
33
34
 
@@ -39,6 +40,10 @@ with built-in traversal and path-finding algorithms.
39
40
 
40
41
  ===============================================================================
41
42
 
43
+ .. image:: https://static.pepy.tech/personalized-badge/core-data-structures?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
44
+ :target: https://pepy.tech/projects/core-data-structures
45
+ :alt: PyPI Downloads
46
+
42
47
  .. image:: https://img.shields.io/pypi/pyversions/core-data-structures.svg
43
48
  :target: https://pypi.org/project/core-data-structures/
44
49
  :alt: Python Versions
@@ -6,6 +6,10 @@ with built-in traversal and path-finding algorithms.
6
6
 
7
7
  ===============================================================================
8
8
 
9
+ .. image:: https://static.pepy.tech/personalized-badge/core-data-structures?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
10
+ :target: https://pepy.tech/projects/core-data-structures
11
+ :alt: PyPI Downloads
12
+
9
13
  .. image:: https://img.shields.io/pypi/pyversions/core-data-structures.svg
10
14
  :target: https://pypi.org/project/core-data-structures/
11
15
  :alt: Python Versions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-data-structures
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: This project/library contains commons data structures...
5
5
  Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
6
6
  Maintainer: Alejandro Cora González
@@ -25,9 +25,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
25
  Requires-Python: >=3.9
26
26
  Description-Content-Type: text/x-rst
27
27
  License-File: LICENSE
28
+ Requires-Dist: core-mixins>=3.2.0
28
29
  Requires-Dist: typing-extensions>=4.8.0
29
30
  Provides-Extra: dev
30
- Requires-Dist: core-dev-tools>=2.0.0; extra == "dev"
31
+ Requires-Dist: core-dev-tools>=2.1.0; extra == "dev"
31
32
  Requires-Dist: core-tests>=2.1.0; extra == "dev"
32
33
  Dynamic: license-file
33
34
 
@@ -39,6 +40,10 @@ with built-in traversal and path-finding algorithms.
39
40
 
40
41
  ===============================================================================
41
42
 
43
+ .. image:: https://static.pepy.tech/personalized-badge/core-data-structures?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
44
+ :target: https://pepy.tech/projects/core-data-structures
45
+ :alt: PyPI Downloads
46
+
42
47
  .. image:: https://img.shields.io/pypi/pyversions/core-data-structures.svg
43
48
  :target: https://pypi.org/project/core-data-structures/
44
49
  :alt: Python Versions
@@ -8,10 +8,13 @@ core_data_structures.egg-info/dependency_links.txt
8
8
  core_data_structures.egg-info/requires.txt
9
9
  core_data_structures.egg-info/top_level.txt
10
10
  data_structures/__init__.py
11
+ data_structures/base.py
11
12
  data_structures/py.typed
12
13
  data_structures/graphs/__init__.py
13
14
  data_structures/graphs/graphs.py
14
15
  data_structures/graphs/vertex.py
16
+ data_structures/lists/__init__.py
17
+ data_structures/lists/singly_linked_list.py
15
18
  data_structures/trees/__init__.py
16
19
  data_structures/trees/binary_tree.py
17
20
  data_structures/trees/simple_tree.py
@@ -1,5 +1,6 @@
1
+ core-mixins>=3.2.0
1
2
  typing-extensions>=4.8.0
2
3
 
3
4
  [dev]
4
- core-dev-tools>=2.0.0
5
+ core-dev-tools>=2.1.0
5
6
  core-tests>=2.1.0
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Base node used as a building block across data structures."""
4
+
5
+ from typing import Generic
6
+ from typing import Optional
7
+ from typing import TypeVar
8
+
9
+
10
+ __all__ = [
11
+ "Node",
12
+ "T",
13
+ ]
14
+
15
+ T = TypeVar("T")
16
+
17
+
18
+ class Node(Generic[T]): # pylint: disable=too-few-public-methods
19
+ """
20
+ Generic container for a single value, meant to be
21
+ subclassed by concrete node types.
22
+ """
23
+
24
+ def __init__(self, value: Optional[T] = None) -> None:
25
+ self._value = value
26
+
27
+ def __repr__(self):
28
+ return f"[{self._value}]"
29
+
30
+ @property
31
+ def value(self) -> Optional[T]:
32
+ """ The value held by the node. """
33
+ return self._value
34
+
35
+ @value.setter
36
+ def value(self, value: T) -> None:
37
+ self._value = value
@@ -7,7 +7,7 @@ from typing import Dict, List
7
7
 
8
8
  if sys.version_info >= (3, 11):
9
9
  from typing import Self
10
- else:
10
+ else: # pragma: no cover
11
11
  from typing_extensions import Self
12
12
 
13
13
 
@@ -0,0 +1,308 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ A linked list is a linear data structure composed of a sequence
5
+ of nodes where each node contains data and a pointer (or reference)
6
+ to the next node. Unlike arrays, elements in a linked list are not
7
+ stored in contiguous memory locations, meaning they can be scattered
8
+ across your system's RAM.
9
+ """
10
+
11
+ from contextlib import suppress
12
+ from typing import Generic, Optional, Iterator
13
+ from typing import cast
14
+
15
+ from core_mixins.compatibility import Self
16
+
17
+ from data_structures.base import Node as BaseNode
18
+ from data_structures.base import T
19
+
20
+
21
+ class Node(BaseNode[T]):
22
+ """
23
+ Node in a singly linked list, holding a value and a
24
+ reference to the next node.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ value: Optional[T] = None,
30
+ next_node: Optional[Self] = None,
31
+ ) -> None:
32
+ super().__init__(value=value)
33
+ self._next = next_node
34
+
35
+ @property
36
+ def next(self) -> Optional[Self]:
37
+ """The next node in the list, if any."""
38
+ return self._next
39
+
40
+ @next.setter
41
+ def next(self, next_node: Optional[Self]) -> None:
42
+ self._next = next_node
43
+
44
+
45
+ class SinglyLinkedList(Generic[T]):
46
+ """
47
+ Singly linked list that tracks its head node and supports
48
+ forward iteration. Positions are 0-indexed.
49
+ """
50
+
51
+ def __init__(self, value: Optional[T] = None) -> None:
52
+ self._head: Optional[Node[T]] = None if value is None else Node(value)
53
+ self._length = 0 if value is None else 1
54
+ self._end = self._head
55
+
56
+ def __len__(self):
57
+ """Returns the length of the list."""
58
+ return self._length
59
+
60
+ def __getitem__(self, item: int) -> T:
61
+ """Returns the value at the given position."""
62
+ return self.get(item)
63
+
64
+ def __iter__(self) -> Iterator[T]:
65
+ """Iterates over the values in the list, starting from the head."""
66
+
67
+ pointer = self._head
68
+ while pointer:
69
+ yield cast(T, pointer.value)
70
+ pointer = pointer.next
71
+
72
+ def __contains__(self, item: T) -> bool:
73
+ with suppress(ValueError):
74
+ self.index(item)
75
+ return True
76
+ return False
77
+
78
+ @classmethod
79
+ def from_list(cls, a_list: list) -> Self:
80
+ """Creates the singly linked list from a python list."""
81
+
82
+ new_list = cls()
83
+ for value in a_list:
84
+ new_list.append(value)
85
+ return new_list
86
+
87
+ @property
88
+ def length(self) -> int:
89
+ """The number of nodes in the list."""
90
+ return self._length
91
+
92
+ @property
93
+ def is_empty(self) -> bool:
94
+ """Whether the list has no nodes."""
95
+ return self._head is None
96
+
97
+ @property
98
+ def head(self) -> Optional[Node[T]]:
99
+ """The first node in the list."""
100
+ return self._head
101
+
102
+ @property
103
+ def end(self) -> Optional[Node[T]]:
104
+ """The end node in the list."""
105
+ return self._end
106
+
107
+ def clear(self) -> None:
108
+ """Removes all nodes from the list."""
109
+ self._head = self._end = None
110
+ self._length = 0
111
+
112
+ def to_list(self) -> list:
113
+ """Materializes the list's values into a python list."""
114
+ return list(self)
115
+
116
+ def _node_at(self, pos: int) -> Node[T]:
117
+ """Returns the actual node at the given position."""
118
+
119
+ if pos < 0 or pos >= self._length:
120
+ raise IndexError("Invalid position!")
121
+
122
+ index, pointer = 0, cast(Node[T], self._head)
123
+ while index < pos:
124
+ pointer = cast(Node[T], pointer.next)
125
+ index += 1
126
+
127
+ return pointer
128
+
129
+ def get(self, pos: int) -> T:
130
+ """Returns the value at the given position."""
131
+ return cast(T, self._node_at(pos).value)
132
+
133
+ def index(self, value: T) -> int:
134
+ """Returns the position of the first occurrence of the given value."""
135
+
136
+ for pos, value_ in enumerate(self):
137
+ if value_ == value:
138
+ return pos
139
+
140
+ raise ValueError(f"{value!r} is not in list")
141
+
142
+ def prepend(self, value: T) -> None:
143
+ """Adds a value to the front of the list."""
144
+
145
+ if self._head is None:
146
+ self.append(value)
147
+
148
+ else:
149
+ self._head = Node(value, next_node=self._head)
150
+ self._length += 1
151
+
152
+ def append(self, value: T) -> None:
153
+ """Adds a value to the end of the list."""
154
+
155
+ new_node = Node(value)
156
+
157
+ if self._end is None:
158
+ self._head = new_node
159
+ else:
160
+ self._end.next = new_node
161
+
162
+ self._end = new_node
163
+ self._length += 1
164
+
165
+ def insert(self, value: T, pos: int) -> None:
166
+ """Inserts a value at the given position."""
167
+
168
+ if pos == 0:
169
+ self.prepend(value)
170
+
171
+ elif pos == self._length:
172
+ self.append(value)
173
+
174
+ else:
175
+ pointer = self._node_at(pos - 1)
176
+ pointer.next = Node(value, next_node=pointer.next)
177
+ self._length += 1
178
+
179
+ def extend(self, a_list: Self) -> None:
180
+ """Appends a copy of each value from another list."""
181
+
182
+ for value in a_list:
183
+ self.append(value)
184
+
185
+ def pop_front(self) -> T:
186
+ """Removes and return the value at the front of the list."""
187
+
188
+ if self.is_empty:
189
+ raise IndexError("Empty list!")
190
+
191
+ head = cast(Node[T], self._head)
192
+ value = cast(T, head.value)
193
+
194
+ if self._length == 1:
195
+ self._head = None
196
+ self._end = None
197
+ else:
198
+ self._head = head.next
199
+
200
+ self._length -= 1
201
+ return value
202
+
203
+ def pop_back(self) -> T:
204
+ """Removes and returns the value at the end of the list."""
205
+
206
+ if self.is_empty:
207
+ raise IndexError("Empty list!")
208
+
209
+ value = cast(T, cast(Node[T], self._end).value)
210
+ if self._length == 1:
211
+ self.clear()
212
+ return value
213
+
214
+ pointer = cast(Node[T], self._head)
215
+ while pointer.next is not self._end:
216
+ pointer = cast(Node[T], pointer.next)
217
+
218
+ pointer.next = None
219
+ self._end = pointer
220
+ self._length -= 1
221
+ return value
222
+
223
+ def pop(self, index: int) -> T:
224
+ """Removes and returns the value at the given position."""
225
+
226
+ if index < 0 or index >= self._length:
227
+ raise IndexError("Index error!")
228
+
229
+ if index == 0:
230
+ return self.pop_front()
231
+
232
+ if index == self._length - 1:
233
+ return self.pop_back()
234
+
235
+ pointer = self._node_at(index - 1)
236
+ removed = cast(Node[T], pointer.next)
237
+ pointer.next = removed.next
238
+ self._length -= 1
239
+ return cast(T, removed.value)
240
+
241
+ def remove(self, value: T, all_values: bool = False) -> None:
242
+ """Removes the first occurrence of the value, or all occurrences if `all_values` is set."""
243
+
244
+ was_found = False
245
+
246
+ while self._head is not None and self._head.value == value:
247
+ self._head = self._head.next
248
+ self._length -= 1
249
+ was_found = True
250
+
251
+ if self._head is None:
252
+ self._end = None
253
+
254
+ if not all_values:
255
+ return
256
+
257
+ if self._head is not None:
258
+ left = self._head
259
+ right = left.next
260
+
261
+ while right:
262
+ if right.value == value:
263
+ left.next = right.next
264
+ self._length -= 1
265
+ was_found = True
266
+
267
+ if right is self._end:
268
+ self._end = left
269
+
270
+ right = left.next
271
+
272
+ if not all_values:
273
+ return
274
+
275
+ else:
276
+ left = right
277
+ right = right.next
278
+
279
+ if not was_found:
280
+ raise ValueError(f"{value!r} is not in list")
281
+
282
+ def reverse(self) -> None:
283
+ """Reverses the list in place."""
284
+
285
+ if self.is_empty or self._length == 1:
286
+ return
287
+
288
+ if self._length == 2:
289
+ head, end = cast(Node[T], self._head), cast(Node[T], self._end)
290
+ self._head, self._end = end, head
291
+ self._head.next = self._end
292
+ self._end.next = None
293
+ return
294
+
295
+ new_end = left = cast(Node[T], self._head)
296
+ new_head = cast(Node[T], new_end.next)
297
+ right = new_head.next
298
+
299
+ while new_head is not self._end:
300
+ new_head.next = left
301
+ left = new_head
302
+ new_head = cast(Node[T], right)
303
+ right = new_head.next
304
+
305
+ new_head.next = left
306
+ new_end.next = None
307
+ self._end = new_end
308
+ self._head = new_head
File without changes
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
  [project]
10
10
  name = "core-data-structures"
11
11
  description = "This project/library contains commons data structures..."
12
- version = "1.2.0"
12
+ version = "1.2.1"
13
13
 
14
14
  authors = [
15
15
  {name = "Alejandro Cora González", email = "alek.cora.glez@gmail.com"}
@@ -40,12 +40,13 @@ classifiers = [
40
40
  ]
41
41
 
42
42
  dependencies = [
43
+ "core-mixins>=3.2.0",
43
44
  "typing-extensions>=4.8.0",
44
45
  ]
45
46
 
46
47
  [project.optional-dependencies]
47
48
  dev = [
48
- "core-dev-tools>=2.0.0",
49
+ "core-dev-tools>=2.1.0",
49
50
  "core-tests>=2.1.0",
50
51
  ]
51
52