Module grscheller.datastructures.dqueue
Module grscheller.datastructure.dqueue - Double sided queue
Double sided queue with amortized O(1) insertions & deletions from either end. Obtaining length (number of elements) of a Dqueue is also a O(1) operation.
Implemented with a Python List based circular array.
Expand source code
# Copyright 2023 Geoffrey R. Scheller
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module grscheller.datastructure.dqueue - Double sided queue
Double sided queue with amortized O(1) insertions & deletions from either end.
Obtaining length (number of elements) of a Dqueue is also a O(1) operation.
Implemented with a Python List based circular array.
"""
from __future__ import annotations
__all__ = ['Dqueue']
__author__ = "Geoffrey R. Scheller"
__copyright__ = "Copyright (c) 2023 Geoffrey R. Scheller"
__license__ = "Appache License 2.0"
from typing import Any, Callable, Self, Union
from .carray import CArray
from .iterlib import concatIters, mapIter, mergeIters
class Dqueue():
"""Double sided queue datastructure. Will resize itself as needed.
Does not throw exceptions. The Dqueue class consistently uses None to
represent the absence of a value. None will not be pushed to this
data structure. As an alternative, use Maybe objects of type Nothing,
or the empty tuple () to represent a non-existent value.
"""
def __init__(self, *ds):
"""Construct a double sided queue"""
self._carray = CArray()
for d in ds:
if d is not None:
self._carray.pushR(d)
def __bool__(self) -> bool:
"""Returns true if dqueue is not empty"""
return len(self._carray) != 0
def __len__(self) -> int:
"""Returns current number of values in dqueue"""
return len(self._carray)
def __iter__(self):
"""Iterator yielding data currently stored in dqueue"""
currCarray = self._carray.copy()
for pos in range(len(currCarray)):
yield currCarray[pos]
def __reversed__(self):
"""Reverse iterate over the current state of the dqueue"""
for data in reversed(self._carray.copy()):
yield data
def __eq__(self, other):
"""Returns True if all the data stored in both compare as equal.
Worst case is O(n) behavior for the true case.
"""
if not isinstance(other, type(self)):
return False
return self._carray == other._carray
def __repr__(self):
"""Display data in dqueue"""
dataListStrs = []
for data in self._carray:
dataListStrs.append(repr(data))
return ">< " + " | ".join(dataListStrs) + " ><"
def copy(self) -> Dqueue:
"""Return shallow copy of the dqueue in O(n) time & space complexity"""
new_dqueue = Dqueue()
new_dqueue._carray = self._carray.copy()
return new_dqueue
def pushR(self, *ds: Any) -> Dqueue:
"""Push data on rear of dqueue & return reference to self"""
for d in ds:
if d != None:
self._carray.pushR(d)
return self
def pushL(self, *ds: Any) -> Dqueue:
"""Push data on front of dqueue, return reference to self"""
for d in ds:
if d != None:
self._carray.pushL(d)
return self
def popR(self) -> Union[Any, None]:
"""Pop data off rear of dqueue"""
if len(self._carray) > 0:
return self._carray.popR()
else:
return None
def popL(self) -> Union[Any, None]:
"""Pop data off front of dqueue"""
if len(self._carray) > 0:
return self._carray.popL()
else:
return None
def peakR(self) -> Union[Any, None]:
"""Return rear element of dqueue without consuming it"""
if len(self._carray) > 0:
return self._carray[-1]
else:
return None
def peakL(self) -> Union[Any, None]:
"""Return front element of dqueue without consuming it"""
if len(self._carray) > 0:
return self._carray[0]
else:
return None
def capacity(self) -> int:
"""Returns current capacity of dqueue"""
return self._carray.capacity()
def fractionFilled(self) -> float:
"""Returns current capacity of dqueue"""
return self._carray.fractionFilled()
def resize(self, addCapacity = 0) -> Self:
"""Compact dqueue and add extra capacity"""
self._carray.resize(addCapacity)
return self
def map(self, f: Callable[[Any], Any]) -> Self:
"""Apply function over dqueue contents"""
self._carray = Dqueue(*mapIter(iter(self), f))._carray
return self
def flatMap(self, f: Callable[[Any], Dqueue]) -> Self:
"""Apply function and flatten result, surpress any None values"""
self._carray = Dqueue(*concatIters(
*mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray
return self
def mergeMap(self, f: Callable[[Any], Dqueue]) -> Self:
"""Apply function and flatten result, surpress any None values"""
self._carray = Dqueue(*mergeIters(
*mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray
return self
if __name__ == "__main__":
pass
Classes
class Dqueue (*ds)
-
Double sided queue datastructure. Will resize itself as needed.
Does not throw exceptions. The Dqueue class consistently uses None to represent the absence of a value. None will not be pushed to this data structure. As an alternative, use Maybe objects of type Nothing, or the empty tuple () to represent a non-existent value.
Construct a double sided queue
Expand source code
class Dqueue(): """Double sided queue datastructure. Will resize itself as needed. Does not throw exceptions. The Dqueue class consistently uses None to represent the absence of a value. None will not be pushed to this data structure. As an alternative, use Maybe objects of type Nothing, or the empty tuple () to represent a non-existent value. """ def __init__(self, *ds): """Construct a double sided queue""" self._carray = CArray() for d in ds: if d is not None: self._carray.pushR(d) def __bool__(self) -> bool: """Returns true if dqueue is not empty""" return len(self._carray) != 0 def __len__(self) -> int: """Returns current number of values in dqueue""" return len(self._carray) def __iter__(self): """Iterator yielding data currently stored in dqueue""" currCarray = self._carray.copy() for pos in range(len(currCarray)): yield currCarray[pos] def __reversed__(self): """Reverse iterate over the current state of the dqueue""" for data in reversed(self._carray.copy()): yield data def __eq__(self, other): """Returns True if all the data stored in both compare as equal. Worst case is O(n) behavior for the true case. """ if not isinstance(other, type(self)): return False return self._carray == other._carray def __repr__(self): """Display data in dqueue""" dataListStrs = [] for data in self._carray: dataListStrs.append(repr(data)) return ">< " + " | ".join(dataListStrs) + " ><" def copy(self) -> Dqueue: """Return shallow copy of the dqueue in O(n) time & space complexity""" new_dqueue = Dqueue() new_dqueue._carray = self._carray.copy() return new_dqueue def pushR(self, *ds: Any) -> Dqueue: """Push data on rear of dqueue & return reference to self""" for d in ds: if d != None: self._carray.pushR(d) return self def pushL(self, *ds: Any) -> Dqueue: """Push data on front of dqueue, return reference to self""" for d in ds: if d != None: self._carray.pushL(d) return self def popR(self) -> Union[Any, None]: """Pop data off rear of dqueue""" if len(self._carray) > 0: return self._carray.popR() else: return None def popL(self) -> Union[Any, None]: """Pop data off front of dqueue""" if len(self._carray) > 0: return self._carray.popL() else: return None def peakR(self) -> Union[Any, None]: """Return rear element of dqueue without consuming it""" if len(self._carray) > 0: return self._carray[-1] else: return None def peakL(self) -> Union[Any, None]: """Return front element of dqueue without consuming it""" if len(self._carray) > 0: return self._carray[0] else: return None def capacity(self) -> int: """Returns current capacity of dqueue""" return self._carray.capacity() def fractionFilled(self) -> float: """Returns current capacity of dqueue""" return self._carray.fractionFilled() def resize(self, addCapacity = 0) -> Self: """Compact dqueue and add extra capacity""" self._carray.resize(addCapacity) return self def map(self, f: Callable[[Any], Any]) -> Self: """Apply function over dqueue contents""" self._carray = Dqueue(*mapIter(iter(self), f))._carray return self def flatMap(self, f: Callable[[Any], Dqueue]) -> Self: """Apply function and flatten result, surpress any None values""" self._carray = Dqueue(*concatIters( *mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray return self def mergeMap(self, f: Callable[[Any], Dqueue]) -> Self: """Apply function and flatten result, surpress any None values""" self._carray = Dqueue(*mergeIters( *mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray return self
Methods
def capacity(self) ‑> int
-
Returns current capacity of dqueue
Expand source code
def capacity(self) -> int: """Returns current capacity of dqueue""" return self._carray.capacity()
def copy(self) ‑> Dqueue
-
Return shallow copy of the dqueue in O(n) time & space complexity
Expand source code
def copy(self) -> Dqueue: """Return shallow copy of the dqueue in O(n) time & space complexity""" new_dqueue = Dqueue() new_dqueue._carray = self._carray.copy() return new_dqueue
def flatMap(self, f: Callable[[Any], Dqueue]) ‑> Self
-
Apply function and flatten result, surpress any None values
Expand source code
def flatMap(self, f: Callable[[Any], Dqueue]) -> Self: """Apply function and flatten result, surpress any None values""" self._carray = Dqueue(*concatIters( *mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray return self
def fractionFilled(self) ‑> float
-
Returns current capacity of dqueue
Expand source code
def fractionFilled(self) -> float: """Returns current capacity of dqueue""" return self._carray.fractionFilled()
def map(self, f: Callable[[Any], Any]) ‑> Self
-
Apply function over dqueue contents
Expand source code
def map(self, f: Callable[[Any], Any]) -> Self: """Apply function over dqueue contents""" self._carray = Dqueue(*mapIter(iter(self), f))._carray return self
def mergeMap(self, f: Callable[[Any], Dqueue]) ‑> Self
-
Apply function and flatten result, surpress any None values
Expand source code
def mergeMap(self, f: Callable[[Any], Dqueue]) -> Self: """Apply function and flatten result, surpress any None values""" self._carray = Dqueue(*mergeIters( *mapIter(mapIter(iter(self), f), lambda x: iter(x))))._carray return self
def peakL(self) ‑> Optional[Any]
-
Return front element of dqueue without consuming it
Expand source code
def peakL(self) -> Union[Any, None]: """Return front element of dqueue without consuming it""" if len(self._carray) > 0: return self._carray[0] else: return None
def peakR(self) ‑> Optional[Any]
-
Return rear element of dqueue without consuming it
Expand source code
def peakR(self) -> Union[Any, None]: """Return rear element of dqueue without consuming it""" if len(self._carray) > 0: return self._carray[-1] else: return None
def popL(self) ‑> Optional[Any]
-
Pop data off front of dqueue
Expand source code
def popL(self) -> Union[Any, None]: """Pop data off front of dqueue""" if len(self._carray) > 0: return self._carray.popL() else: return None
def popR(self) ‑> Optional[Any]
-
Pop data off rear of dqueue
Expand source code
def popR(self) -> Union[Any, None]: """Pop data off rear of dqueue""" if len(self._carray) > 0: return self._carray.popR() else: return None
def pushL(self, *ds: Any) ‑> Dqueue
-
Push data on front of dqueue, return reference to self
Expand source code
def pushL(self, *ds: Any) -> Dqueue: """Push data on front of dqueue, return reference to self""" for d in ds: if d != None: self._carray.pushL(d) return self
def pushR(self, *ds: Any) ‑> Dqueue
-
Push data on rear of dqueue & return reference to self
Expand source code
def pushR(self, *ds: Any) -> Dqueue: """Push data on rear of dqueue & return reference to self""" for d in ds: if d != None: self._carray.pushR(d) return self
def resize(self, addCapacity=0) ‑> Self
-
Compact dqueue and add extra capacity
Expand source code
def resize(self, addCapacity = 0) -> Self: """Compact dqueue and add extra capacity""" self._carray.resize(addCapacity) return self