Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uSTL: Queue, Deque and Pair #39

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
122 changes: 122 additions & 0 deletions examples/udeque.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# UDeque
## Introduction

UDeque is class which is simplifying working with deque.
bleudev marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (documentation): Typo in UDeque Introduction

UDeque is a class which simplifies working with deque.

It has many methods, properties, magic methods.
bleudev marked this conversation as resolved.
Show resolved Hide resolved

Firstly, import `UDeque` from `ufpy`
```python
from ufpy import UDeque
```

## Create UDeque

For creating UDeque you should use this code:
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d = UDeque(1, 2, 3, 4, 5)
```

## Get end/begin

To get end you can use:
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d[0] # 1
d.end() # 1
```

To get begin you can use:
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d[1] # 5
d.begin() # 5
```

> [!NOTE]
> 0 - first element
> 1 - last element
Comment on lines +34 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (documentation): Clarification in UDeque Get end/begin Section

Clarify that 0 refers to the first element and 1 refers to the last element in the context of the end and begin methods.

Suggested change
> 0 - first element
> 1 - last element
> 0 - refers to the first element
> 1 - refers to the last element


## Add end/begin

To add end you can use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.addend(6) # [1, 2, 3, 4, 5, 6]
```

To add begin you can use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.addbegin(0) # [0, 1, 2, 3, 4, 5, 6]
```

## Set end/begin

To set end you can use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.setend(7) # [0, 1, 2, 3, 4, 5, 7]
```

To set begin you can use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.setbegin(7) # [7, 1, 2, 3, 4, 5, 7]
```
> [!NOTE]
> Also you can use indexes:
> ```python
> d[0] = 1 # [1, 1, 2, 3, 4, 5, 7]
> d[1] = 1 # [1, 1, 2, 3, 4, 5, 1]
> ```
> But it is undesirable to use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (documentation): Clarification in UDeque Add end/begin Section

Expand on why it is undesirable to use indexes directly.

Suggested change
> But it is undesirable to use
> But it is undesirable to use indexes directly because it can lead to errors and reduce code readability. Instead, consider using methods provided by the deque class to manipulate elements.


## Delete end/begin

For deleting end use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.popend() # [7, 1, 2, 3, 4, 5]
```

For deleting begin use
bleudev marked this conversation as resolved.
Show resolved Hide resolved
```python
d.popbegin(7) # [1, 2, 3, 4, 5]
```

> [!NOTE]
> To delete end or begin you also can use `del`:
> ```python
> del d[0] # [2, 3, 4, 5]
> del d[1] # [2, 3, 4]
> ```
> But it is undesirable to use

## Get length of deque

You can get the length of the deque using the built-in len() function.

```python
d2 = UDeque(1, 2, 3, 4, 5)
len(d2) # 5
```

## Reserve
To reserve the deque's end and beginning, use the built-in `reserved()` function
```python
reserved(d2) # [5, 1]
```

> [!NOTE]
> `reserved()` returns `[end, begin]`

## Iteration
`UDeque()` suppots iteration:
```python
for var in d2:
print(var)
# 1
# 2
# 3
# 4
# 5
```

> [!NOTE]
> After using `for` your deque will be empty:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (documentation): Question on UDeque Iteration Section

Is it necessary to mention that the deque will be empty after iteration? This behavior might be unexpected and should be highlighted more prominently if it is indeed the case.

> ```python
> print(d2) # []
> ```
72 changes: 72 additions & 0 deletions examples/upair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# UPair

## Introduction

UDeque is class which is simplifying working with pair.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (documentation): Typo in UPair Introduction

UPair is a class which simplifies working with pairs.

It has many methods, properties, magic methods.

Firstly, import `UPair` from `ufpy`
```python
from ufpy import UPair
```

## Create UPair

For creating UPair you should use this code:
```python
p = UPair(first="first", second="second")
```

## Get first/second

To get the first value you can use:
```python
p[0] # first
p.first # first
```

To get the second value you can use:
```python
p[1] # second
p.second # second
```

> [!NOTE]
> 0 - the first value
> 1 - the second value

## Set first/second

To set the first value you can use
```python
p.first = "FIRST" # FIRST
```

Use the same way to set the second value

> [!NOTE]
> Also you can use indexes:
> ```python
> p[0] = "FIRST"
> p[1] = "SECOND"
> ```
> But it is undesirable to use

## Get length of pair

You can get the length of the pair using the built-in len() function.

```python
p2 = UPair(1, 2)
len(p2) # 2
```

> [!NOTE]
> If `first == None` and `second == "second"` `len()` returns 1
> If `first == None` and `second == None` `len()` returns 0

## Reserve
To reserve the pair's the first and the second value, use the built-in `reserved()` function
```python
reserved(p2) # ["second", "first"]
```
78 changes: 78 additions & 0 deletions examples/uqueue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# UQueue
## Introduction

UQueue is class which is simplifying working with queue.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (documentation): Typo in UQueue Introduction

UQueue is a class which simplifies working with queue.

It has many methods, properties, magic methods.

Firstly, import `UQueue` from `ufpy`
```python
from ufpy import UQueue
```

## Create UQueue

For creating UQueue you should use this code:
```python
q = UQueue(1, 2, 3, 4, 5)
```

## Get head

To get head of the queue use:
```python
q.head # 5
```

## Add value

To add value you can use
```python
q.push(6) # [1, 2, 3, 4, 5, 6]
```

## Set head

To set end you can use
```python
q.set_head(7) # [1, 2, 3, 4, 5, 7]
```

## Delete value

For deleting the first element use
```python
q.pop() # [2, 3, 4, 5, 7]
```

## Get length of queue

You can get the length of the queue using the built-in len() function.

```python
q2 = UQueue(1, 2, 3, 4, 5)
len(q2) # 5
```

## Reserve
To reserve the queue's end and beginning, use the built-in `reserved()` function
```python
reserved(q2) # [5, 4, 3, 2, 1]
```

## Iteration
`UQueue()` suppots iteration:
```python
for var in q2:
print(var)
# 1
# 2
# 3
# 4
# 5
```

> [!NOTE]
> After using `for` your queue will be empty:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (documentation): Question on UQueue Iteration Section

Is it necessary to mention that the queue will be empty after iteration? This behavior might be unexpected and should be highlighted more prominently if it is indeed the case.

> ```python
> print(q2) # []
> ```
114 changes: 114 additions & 0 deletions ufpy/udeque.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from __future__ import annotations
from typing import TypeVar, Generic, Any

__all__ = (
"UDeque",
)

VT = TypeVar("VT")

class UDeque(Generic[VT]):
def __init__(self, *__list):
self.__list = list(__list)

def addend(self, value: VT) -> VT:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Redundant check for self in addend method

The check if self: is redundant in the addend method. The method should always append the value to the list without checking if the deque is non-empty.

if self:
self.__list.append(value)
return value
else:
raise IndexError("index out of range")

def addbegin(self, value: VT) -> VT:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Redundant check for self in addbegin method

The check if self: is redundant in the addbegin method. The method should always insert the value at the beginning of the list without checking if the deque is non-empty.

if self:
self.__list.insert(0, value)
return value
else:
raise IndexError("index out of range")

def popend(self) -> VT:
if self:
return self.__list.pop()
else:
raise IndexError("index out of range")

def popbegin(self) -> VT:
if self:
return self.__list.pop(0)
else:
raise IndexError("index out of range")

def setend(self, value: VT) -> VT:
if self:
self[-1] = value
return value
else:
raise IndexError("index out of range")

def setbegin(self, value: VT) -> VT:
if self:
self[0] = value
return value
else:
raise IndexError("index out of range")

def end(self) -> Any:
return self.__list[-1] if self else None

def begin(self) -> Any:
return self.__list[0] if self else None

def copy(self) -> UDeque:
return UDeque(self.__list.copy())

def is_empty(self) -> bool:
return len(self) == 0

def reversed(self) -> UDeque:
return self.__reversed__()
bleudev marked this conversation as resolved.
Show resolved Hide resolved

def __len__(self) -> int:
return len(self.__list)

def __nonzero__(self) -> bool:
return not self.is_empty()

def __getitem__(self, index: Any) -> VT:
if isinstance(index, int):
if index in (0, 1):
return self.__list[index]
else:
raise IndexError(f"{index} out of range (0, 1)")
bleudev marked this conversation as resolved.
Show resolved Hide resolved
bleudev marked this conversation as resolved.
Show resolved Hide resolved
bleudev marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Incorrect index range check in getitem

The index range check in __getitem__ should allow for any valid index within the list, not just 0 and 1. This will cause an IndexError for valid indices beyond 1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Incorrect index range check in setitem

The index range check in __setitem__ should allow for any valid index within the list, not just 0 and 1. This will cause an IndexError for valid indices beyond 1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Incorrect index range check in delitem

The index range check in __delitem__ should allow for any valid index within the list, not just 0 and 1. This will cause an IndexError for valid indices beyond 1.


def __setitem__(self, index: int, value: VT):
if isinstance(index, int):
if index == 0:
self.__list[index] = value
elif index == 1:
self.__list[-index] = value
else:
raise IndexError(f"{index} out of range (0, 1)")

def __delitem__(self, index: int):
if isinstance(index, int):
if index == 0:
del self.__list[index]
elif index == 1:
del self.__list[-index]
else:
raise IndexError(f"{index} out of range (0, 1)")

def __reversed__(self) -> UDeque:
return UDeque((self.end(), self.begin()))
bleudev marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +87 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Incorrect reversed implementation

The __reversed__ method should return a deque with elements in reverse order, not just the end and begin elements.


def __str__(self) -> str:
return str(self.__list)

def __iter__(self) -> UDeque:
return self

def __next__(self) -> VT:
if self.is_empty():
raise StopIteration
else:
value = self.popbegin()
return value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
value = self.popbegin()
return value
return self.popbegin()

Loading
Loading