201 lines
5.4 KiB
Python
201 lines
5.4 KiB
Python
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
from typing import Generic, TypeVar, Iterable, Union, List
|
|
|
|
T = TypeVar("T")
|
|
|
|
@dataclass
|
|
class Node(Generic[T]):
|
|
data: T
|
|
next: Node[T] = None
|
|
|
|
def __repr__(self) -> str:
|
|
return str(self.data)
|
|
|
|
class LinkedList(Generic[T]):
|
|
def __init__(self, initialValues: Iterable[T]):
|
|
self.head: Node[T] = None
|
|
self.tail: Node[T] = None
|
|
|
|
self.extend(initialValues)
|
|
|
|
def __iter__(self) -> Iterable[T]:
|
|
"""Traverse the linked list."""
|
|
node = self.head
|
|
|
|
while node is not None:
|
|
yield node
|
|
node = node.next
|
|
|
|
def __getitem__(self, index: int) -> Node[T]:
|
|
"""Get an item by its index."""
|
|
if index > len(self) - 1:
|
|
raise IndexError("Out of bounds")
|
|
|
|
for i, node in enumerate(self):
|
|
if i == index:
|
|
return node
|
|
|
|
def __setitem__(self, index: int, data: T):
|
|
"""Set an item by its index."""
|
|
if index > len(self) - 1:
|
|
raise IndexError("Out of bounds")
|
|
|
|
for i in range(len(self)):
|
|
if i == index:
|
|
self[i].data = data
|
|
break
|
|
|
|
def __delitem__(self, index: int):
|
|
"""Delete an item using its index."""
|
|
if index > len(self) - 1:
|
|
raise IndexError("Out of bounds")
|
|
|
|
for i in range(len(self)):
|
|
if i == index:
|
|
for j in range(1, len(self) - i):
|
|
self[i + j - 1] = self[i + j].data
|
|
|
|
self[len(self) - 2].next = None
|
|
break
|
|
|
|
def __add__(self, data: Union[T, List[T], LinkedList[T]]) -> LinkedList[T]:
|
|
copy = self.copy()
|
|
|
|
if isinstance(data, LinkedList) or type(data) == list:
|
|
return copy.extend(iter(data) if type(data) == list else iter(map(lambda x: x.data, data)))
|
|
else:
|
|
return copy.append(data)
|
|
|
|
def __len__(self) -> int:
|
|
"""Get the length of the linked list."""
|
|
count = 0
|
|
|
|
for _ in self:
|
|
count += 1
|
|
|
|
return count
|
|
|
|
def append(self, value: T) -> LinkedList[T]:
|
|
"""Append data to the end of the linked list."""
|
|
node = Node(value)
|
|
|
|
if self.head is None:
|
|
self.head = node
|
|
return self
|
|
|
|
for currentNode in self:
|
|
pass
|
|
|
|
currentNode.next = node
|
|
|
|
return self
|
|
|
|
def clear(self) -> LinkedList[T]:
|
|
"""Clear the linked list."""
|
|
self.head = None
|
|
self.tail = None
|
|
return self
|
|
|
|
def count(self, value: T) -> int:
|
|
"""Count the number of occurrences of a value."""
|
|
count = 0
|
|
|
|
for node in self:
|
|
if node.data == value:
|
|
count += 1
|
|
|
|
return count
|
|
|
|
def extend(self, iterable: Iterable[T]) -> LinkedList[T]:
|
|
"""Extend the list from an iterable."""
|
|
for value in iterable:
|
|
self.append(value)
|
|
|
|
return self
|
|
|
|
def index(self, value: T) -> int:
|
|
"""Finds the first index of a value. Returns -1 if the value is not in the list."""
|
|
for i, node in enumerate(self):
|
|
if node.data == value:
|
|
return i
|
|
|
|
return -1
|
|
|
|
def insert(self, index: int, value: T) -> LinkedList[T]:
|
|
"""Inserts a value before an index."""
|
|
if index > len(self) - 1:
|
|
raise IndexError("Out of bounds")
|
|
|
|
for i in range(len(self)):
|
|
if i == index:
|
|
container = value
|
|
|
|
for j in range(len(self)):
|
|
try:
|
|
temp = self[i + j].data
|
|
self[i + j].data = container
|
|
container = temp
|
|
except IndexError:
|
|
self.append(container)
|
|
|
|
break
|
|
|
|
return self
|
|
|
|
def pop(self) -> Node[T]:
|
|
"""Pop and return the final element of the list."""
|
|
for node in self:
|
|
pass
|
|
|
|
del self[len(self) - 1]
|
|
|
|
return node
|
|
|
|
def remove(self, value: T) -> LinkedList[T]:
|
|
for i, node in enumerate(self):
|
|
if node.data == value:
|
|
del self[i]
|
|
return self
|
|
|
|
raise ValueError("Value not found")
|
|
|
|
def copy(self) -> LinkedList[T]:
|
|
"""Returns a copy of the list."""
|
|
return LinkedList[T](iter(map(lambda x: x.data, self)))
|
|
|
|
def sort(self) -> LinkedList[T]:
|
|
n = len(self)
|
|
swapped = False
|
|
|
|
for i in range(n - 1):
|
|
for j in range(0, n - i - 1):
|
|
if self[j].data > self[j + 1].data:
|
|
swapped = True
|
|
self[j], self[j + 1] = self[j + 1].data, self[j].data
|
|
|
|
if not swapped:
|
|
break
|
|
|
|
return self
|
|
|
|
def __repr__(self) -> str:
|
|
out = "["
|
|
|
|
for i, node in enumerate(self):
|
|
value = node.data
|
|
|
|
out += f'"{value}"' if type(value) == str else value
|
|
|
|
if i != len(self) - 1:
|
|
out += ", "
|
|
|
|
return out + "]"
|
|
|
|
names = LinkedList[str](["John Doe", "Jane Doe"])
|
|
names.extend(["Alfred", "Sophie"]).insert(1, "John Snow")
|
|
names.remove("Alfred")
|
|
names += "Woody"
|
|
names.sort()
|
|
|
|
print(names)
|