grscheller.datastructures.queues
Queue based datastructures.
- stateful queue data structures with amortized O(1) pushes and pops each end
- obtaining length (number of elements) of a queue is an O(1) operation
- implemented in a "has-a" relationship with a Python list based circular array
- these data structures will resize themselves larger as needed
Queue types:
- FIFOQueue: First-In-First-Out Queue
- LIFOQueue: Last-In-First-Out Queue
- DoubleQueue: Double-Ended Queue
1# Copyright 2023-2024 Geoffrey R. Scheller 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""### Queue based datastructures. 16 17* stateful queue data structures with amortized O(1) pushes and pops each end 18* obtaining length (number of elements) of a queue is an O(1) operation 19* implemented in a "has-a" relationship with a Python list based circular array 20* these data structures will resize themselves larger as needed 21 22##### Queue types: 23 24* **FIFOQueue:** First-In-First-Out Queue 25* **LIFOQueue:** Last-In-First-Out Queue 26* **DoubleQueue:** Double-Ended Queue 27 28""" 29 30from __future__ import annotations 31 32from typing import Callable, cast, Iterator, Optional 33from grscheller.circular_array.ca import CA 34from grscheller.fp.err_handling import MB 35 36__all__ = [ 'DoubleQueue', 'FIFOQueue', 'LIFOQueue', 'QueueBase' ] 37 38class QueueBase[D](): 39 """#### Base class for circular area based queues. 40 41 * primarily for DRY inheritance 42 * implemented with a grscheller.circular-array (has-a) 43 * order of initial data retained 44 45 """ 46 __slots__ = '_ca' 47 48 def __init__(self, *ds: D): 49 self._ca = CA(*ds) 50 51 def __repr__(self) -> str: 52 if len(self) == 0: 53 return type(self).__name__ + '()' 54 else: 55 return type(self).__name__ + '(' + ', '.join(map(repr, self._ca)) + ')' 56 57 def __bool__(self) -> bool: 58 return len(self._ca) > 0 59 60 def __len__(self) -> int: 61 return len(self._ca) 62 63 def __eq__(self, other: object) -> bool: 64 if not isinstance(other, type(self)): 65 return False 66 return self._ca == other._ca 67 68class FIFOQueue[D](QueueBase[D]): 69 """#### FIFO Queue 70 71 * stateful First-In-First-Out (FIFO) data structure 72 * initial data pushed on in natural FIFO order 73 74 """ 75 __slots__ = () 76 77 def __iter__(self) -> Iterator[D]: 78 return iter(list(self._ca)) 79 80 def copy(self) -> FIFOQueue[D]: 81 """Return a shallow copy of the `FIFOQueue`.""" 82 return FIFOQueue(*self._ca) 83 84 def __str__(self) -> str: 85 return "<< " + " < ".join(map(str, self)) + " <<" 86 87 def push(self, *ds: D) -> None: 88 """Push data onto `FIFOQueue`. 89 90 * like a Python List, does not return a value 91 92 """ 93 self._ca.pushR(*ds) 94 95 def pop(self) -> MB[D]: 96 """Pop data from `FIFOQueue`. 97 98 * pop item off queue, return item in a maybe monad 99 * returns an empty `MB()` if queue is empty 100 101 """ 102 if self._ca: 103 return MB(self._ca.popL()) 104 else: 105 return MB() 106 107 def peak_last_in(self) -> MB[D]: 108 """Peak last data into `FIFOQueue`. 109 110 * return a maybe monad of the last item pushed to queue 111 * does not consume the data 112 * if item already popped, return `MB()` 113 114 """ 115 if self._ca: 116 return MB(self._ca[-1]) 117 else: 118 return MB() 119 120 def peak_next_out(self) -> MB[D]: 121 """Peak next data out of `FIFOQueue`. 122 123 * returns a maybe monad of the next item to be popped from the queue. 124 * does not consume it the item 125 * returns `MB()` if queue is empty 126 127 """ 128 if self._ca: 129 return MB(self._ca[0]) 130 else: 131 return MB() 132 133 def fold[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 134 """Fold `FIFOQueue` in natural order. 135 136 Reduce with `f` using an optional initial value. 137 138 * folds in natural FIFO Order (oldest to newest) 139 * note that when an initial value is not given then `~L = ~D` 140 * if iterable empty & no initial value given, return `MB()` 141 * traditional FP type order given for function `f` 142 143 """ 144 if initial is None: 145 if not self._ca: 146 return MB() 147 return MB(self._ca.foldL(f, initial=initial)) 148 149 def map[U](self, f: Callable[[D], U]) -> FIFOQueue[U]: 150 """Map over the `FIFOQueue`. 151 152 * map function `f` over the queue 153 * oldest to newest 154 * retain original order 155 * returns a new instance 156 157 """ 158 return FIFOQueue(*map(f, self._ca)) 159 160class LIFOQueue[D](QueueBase[D]): 161 """#### LIFO Queue 162 163 * stateful Last-In-First-Out (LIFO) data structure 164 * initial data pushed on in natural LIFO order 165 166 """ 167 __slots__ = () 168 169 def __iter__(self) -> Iterator[D]: 170 return reversed(list(self._ca)) 171 172 def __str__(self) -> str: 173 return "|| " + " > ".join(map(str, self)) + " ><" 174 175 def copy(self) -> LIFOQueue[D]: 176 """Return a shallow copy of the `LIFOQueue`.""" 177 return LIFOQueue(*reversed(self._ca)) 178 179 def push(self, *ds: D) -> None: 180 """Push data onto `LIFOQueue`. 181 182 * like a Python List, does not return a value 183 184 """ 185 self._ca.pushR(*ds) 186 187 def pop(self) -> MB[D]: 188 """Pop data from `LIFOQueue`. 189 190 * pop item off of queue, return item in a maybe monad 191 * returns an empty `MB()` if queue is empty 192 193 """ 194 if self._ca: 195 return MB(self._ca.popR()) 196 else: 197 return MB() 198 199 def peak(self) -> MB[D]: 200 """Peak next data out of `LIFOQueue`. 201 202 * return a maybe monad of the next item to be popped from the queue 203 * does not consume the item 204 * returns `MB()` if queue is empty 205 206 """ 207 if self._ca: 208 return MB(self._ca[-1]) 209 else: 210 return MB() 211 212 def fold[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 213 """Fold `LIFOQueue` in natural order. 214 215 Reduce with `f` using an optional initial value. 216 217 * folds in natural LIFO Order (newest to oldest) 218 * note that when an initial value is not given then `~R = ~D` 219 * if iterable empty & no initial value given, return `MB()` 220 * traditional FP type order given for function `f` 221 222 """ 223 if initial is None: 224 if not self._ca: 225 return MB() 226 return MB(self._ca.foldR(f, initial=initial)) 227 228 def map[U](self, f: Callable[[D], U]) -> LIFOQueue[U]: 229 """Map Over the `LIFOQueue`. 230 231 * map the function `f` over the queue 232 * newest to oldest 233 * retain original order 234 * returns a new instance 235 236 """ 237 return LIFOQueue(*reversed(CA(*map(f, reversed(self._ca))))) 238 239class DoubleQueue[D](QueueBase[D]): 240 """#### Double Ended Queue 241 242 * stateful Double-Ended (DEQueue) data structure 243 * order of initial data retained 244 245 """ 246 __slots__ = () 247 248 def __iter__(self) -> Iterator[D]: 249 return iter(list(self._ca)) 250 251 def __reversed__(self) -> Iterator[D]: 252 return reversed(list(self._ca)) 253 254 def __str__(self) -> str: 255 return ">< " + " | ".join(map(str, self)) + " ><" 256 257 def copy(self) -> DoubleQueue[D]: 258 """Return a shallow copy of the `DoubleQueue`.""" 259 return DoubleQueue(*self._ca) 260 261 def pushL(self, *ds: D) -> None: 262 """Push data onto left side (front) of `DoubleQueue`. 263 264 * like a Python List, does not return a value 265 266 """ 267 self._ca.pushL(*ds) 268 269 def pushR(self, *ds: D) -> None: 270 """Push data onto right side (rear) of `DoubleQueue`. 271 272 * like a Python List, does not return a value 273 274 """ 275 self._ca.pushR(*ds) 276 277 def popL(self) -> MB[D]: 278 """Pop Data from left side (front) of `DoubleQueue`. 279 280 * pop left most item off of queue, return item in a maybe monad 281 * returns an empty `MB()` if queue is empty 282 283 """ 284 if self._ca: 285 return MB(self._ca.popL()) 286 else: 287 return MB() 288 289 def popR(self) -> MB[D]: 290 """Pop Data from right side (rear) of `DoubleQueue`. 291 292 * pop right most item off of queue, return item in a maybe monad 293 * returns an empty `MB()` if queue is empty 294 295 """ 296 if self._ca: 297 return MB(self._ca.popR()) 298 else: 299 return MB() 300 301 def peakL(self) -> MB[D]: 302 """Peak left side of `DoubleQueue`. 303 304 * return left most value in a maybe monad 305 * does not consume the item 306 * returns an empty `MB()` if queue is empty 307 308 """ 309 if self._ca: 310 return MB(self._ca[0]) 311 else: 312 return MB() 313 314 def peakR(self) -> MB[D]: 315 """Peak right side of `DoubleQueue`. 316 317 * return right most value in a maybe monad 318 * does not consume the item 319 * returns an empty `MB()` if queue is empty 320 321 """ 322 if self._ca: 323 return MB(self._ca[-1]) 324 else: 325 return MB() 326 327 def foldL[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 328 """Fold `DoubleQueue` left to right. 329 330 Reduce left with `f` using an optional initial value. 331 332 * note that when an initial value is not given then `~L = ~D` 333 * if iterable empty & no initial value given, return `MB()` 334 * traditional FP type order given for function `f` 335 336 """ 337 if initial is None: 338 if not self._ca: 339 return MB() 340 return MB(self._ca.foldL(f, initial=initial)) 341 342 def foldR[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 343 """Fold `DoubleQueue` right to left. 344 345 Reduce right with `f` using an optional initial value. 346 347 * note that when an initial value is not given then `~R = ~D` 348 * if iterable empty & no initial value given, return `MB()` 349 * traditional FP type order given for function `f` 350 351 """ 352 if initial is None: 353 if not self._ca: 354 return MB() 355 return MB(self._ca.foldR(f, initial=initial)) 356 357 def map[U](self, f: Callable[[D], U]) -> DoubleQueue[U]: 358 """`Map a function over `DoubleQueue`. 359 360 * map the function `f` over the `DoubleQueue` 361 * left to right 362 * retain original order 363 * returns a new instance 364 365 """ 366 return DoubleQueue(*map(f, self._ca))
240class DoubleQueue[D](QueueBase[D]): 241 """#### Double Ended Queue 242 243 * stateful Double-Ended (DEQueue) data structure 244 * order of initial data retained 245 246 """ 247 __slots__ = () 248 249 def __iter__(self) -> Iterator[D]: 250 return iter(list(self._ca)) 251 252 def __reversed__(self) -> Iterator[D]: 253 return reversed(list(self._ca)) 254 255 def __str__(self) -> str: 256 return ">< " + " | ".join(map(str, self)) + " ><" 257 258 def copy(self) -> DoubleQueue[D]: 259 """Return a shallow copy of the `DoubleQueue`.""" 260 return DoubleQueue(*self._ca) 261 262 def pushL(self, *ds: D) -> None: 263 """Push data onto left side (front) of `DoubleQueue`. 264 265 * like a Python List, does not return a value 266 267 """ 268 self._ca.pushL(*ds) 269 270 def pushR(self, *ds: D) -> None: 271 """Push data onto right side (rear) of `DoubleQueue`. 272 273 * like a Python List, does not return a value 274 275 """ 276 self._ca.pushR(*ds) 277 278 def popL(self) -> MB[D]: 279 """Pop Data from left side (front) of `DoubleQueue`. 280 281 * pop left most item off of queue, return item in a maybe monad 282 * returns an empty `MB()` if queue is empty 283 284 """ 285 if self._ca: 286 return MB(self._ca.popL()) 287 else: 288 return MB() 289 290 def popR(self) -> MB[D]: 291 """Pop Data from right side (rear) of `DoubleQueue`. 292 293 * pop right most item off of queue, return item in a maybe monad 294 * returns an empty `MB()` if queue is empty 295 296 """ 297 if self._ca: 298 return MB(self._ca.popR()) 299 else: 300 return MB() 301 302 def peakL(self) -> MB[D]: 303 """Peak left side of `DoubleQueue`. 304 305 * return left most value in a maybe monad 306 * does not consume the item 307 * returns an empty `MB()` if queue is empty 308 309 """ 310 if self._ca: 311 return MB(self._ca[0]) 312 else: 313 return MB() 314 315 def peakR(self) -> MB[D]: 316 """Peak right side of `DoubleQueue`. 317 318 * return right most value in a maybe monad 319 * does not consume the item 320 * returns an empty `MB()` if queue is empty 321 322 """ 323 if self._ca: 324 return MB(self._ca[-1]) 325 else: 326 return MB() 327 328 def foldL[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 329 """Fold `DoubleQueue` left to right. 330 331 Reduce left with `f` using an optional initial value. 332 333 * note that when an initial value is not given then `~L = ~D` 334 * if iterable empty & no initial value given, return `MB()` 335 * traditional FP type order given for function `f` 336 337 """ 338 if initial is None: 339 if not self._ca: 340 return MB() 341 return MB(self._ca.foldL(f, initial=initial)) 342 343 def foldR[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 344 """Fold `DoubleQueue` right to left. 345 346 Reduce right with `f` using an optional initial value. 347 348 * note that when an initial value is not given then `~R = ~D` 349 * if iterable empty & no initial value given, return `MB()` 350 * traditional FP type order given for function `f` 351 352 """ 353 if initial is None: 354 if not self._ca: 355 return MB() 356 return MB(self._ca.foldR(f, initial=initial)) 357 358 def map[U](self, f: Callable[[D], U]) -> DoubleQueue[U]: 359 """`Map a function over `DoubleQueue`. 360 361 * map the function `f` over the `DoubleQueue` 362 * left to right 363 * retain original order 364 * returns a new instance 365 366 """ 367 return DoubleQueue(*map(f, self._ca))
Double Ended Queue
- stateful Double-Ended (DEQueue) data structure
- order of initial data retained
258 def copy(self) -> DoubleQueue[D]: 259 """Return a shallow copy of the `DoubleQueue`.""" 260 return DoubleQueue(*self._ca)
Return a shallow copy of the DoubleQueue
.
262 def pushL(self, *ds: D) -> None: 263 """Push data onto left side (front) of `DoubleQueue`. 264 265 * like a Python List, does not return a value 266 267 """ 268 self._ca.pushL(*ds)
Push data onto left side (front) of DoubleQueue
.
- like a Python List, does not return a value
270 def pushR(self, *ds: D) -> None: 271 """Push data onto right side (rear) of `DoubleQueue`. 272 273 * like a Python List, does not return a value 274 275 """ 276 self._ca.pushR(*ds)
Push data onto right side (rear) of DoubleQueue
.
- like a Python List, does not return a value
278 def popL(self) -> MB[D]: 279 """Pop Data from left side (front) of `DoubleQueue`. 280 281 * pop left most item off of queue, return item in a maybe monad 282 * returns an empty `MB()` if queue is empty 283 284 """ 285 if self._ca: 286 return MB(self._ca.popL()) 287 else: 288 return MB()
Pop Data from left side (front) of DoubleQueue
.
- pop left most item off of queue, return item in a maybe monad
- returns an empty
MB()
if queue is empty
290 def popR(self) -> MB[D]: 291 """Pop Data from right side (rear) of `DoubleQueue`. 292 293 * pop right most item off of queue, return item in a maybe monad 294 * returns an empty `MB()` if queue is empty 295 296 """ 297 if self._ca: 298 return MB(self._ca.popR()) 299 else: 300 return MB()
Pop Data from right side (rear) of DoubleQueue
.
- pop right most item off of queue, return item in a maybe monad
- returns an empty
MB()
if queue is empty
302 def peakL(self) -> MB[D]: 303 """Peak left side of `DoubleQueue`. 304 305 * return left most value in a maybe monad 306 * does not consume the item 307 * returns an empty `MB()` if queue is empty 308 309 """ 310 if self._ca: 311 return MB(self._ca[0]) 312 else: 313 return MB()
Peak left side of DoubleQueue
.
- return left most value in a maybe monad
- does not consume the item
- returns an empty
MB()
if queue is empty
315 def peakR(self) -> MB[D]: 316 """Peak right side of `DoubleQueue`. 317 318 * return right most value in a maybe monad 319 * does not consume the item 320 * returns an empty `MB()` if queue is empty 321 322 """ 323 if self._ca: 324 return MB(self._ca[-1]) 325 else: 326 return MB()
Peak right side of DoubleQueue
.
- return right most value in a maybe monad
- does not consume the item
- returns an empty
MB()
if queue is empty
328 def foldL[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 329 """Fold `DoubleQueue` left to right. 330 331 Reduce left with `f` using an optional initial value. 332 333 * note that when an initial value is not given then `~L = ~D` 334 * if iterable empty & no initial value given, return `MB()` 335 * traditional FP type order given for function `f` 336 337 """ 338 if initial is None: 339 if not self._ca: 340 return MB() 341 return MB(self._ca.foldL(f, initial=initial))
Fold DoubleQueue
left to right.
Reduce left with f
using an optional initial value.
- note that when an initial value is not given then
~L = ~D
- if iterable empty & no initial value given, return
MB()
- traditional FP type order given for function
f
343 def foldR[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 344 """Fold `DoubleQueue` right to left. 345 346 Reduce right with `f` using an optional initial value. 347 348 * note that when an initial value is not given then `~R = ~D` 349 * if iterable empty & no initial value given, return `MB()` 350 * traditional FP type order given for function `f` 351 352 """ 353 if initial is None: 354 if not self._ca: 355 return MB() 356 return MB(self._ca.foldR(f, initial=initial))
Fold DoubleQueue
right to left.
Reduce right with f
using an optional initial value.
- note that when an initial value is not given then
~R = ~D
- if iterable empty & no initial value given, return
MB()
- traditional FP type order given for function
f
358 def map[U](self, f: Callable[[D], U]) -> DoubleQueue[U]: 359 """`Map a function over `DoubleQueue`. 360 361 * map the function `f` over the `DoubleQueue` 362 * left to right 363 * retain original order 364 * returns a new instance 365 366 """ 367 return DoubleQueue(*map(f, self._ca))
Map a function over
DoubleQueue`.
- map the function
f
over theDoubleQueue
- left to right
- retain original order
- returns a new instance
69class FIFOQueue[D](QueueBase[D]): 70 """#### FIFO Queue 71 72 * stateful First-In-First-Out (FIFO) data structure 73 * initial data pushed on in natural FIFO order 74 75 """ 76 __slots__ = () 77 78 def __iter__(self) -> Iterator[D]: 79 return iter(list(self._ca)) 80 81 def copy(self) -> FIFOQueue[D]: 82 """Return a shallow copy of the `FIFOQueue`.""" 83 return FIFOQueue(*self._ca) 84 85 def __str__(self) -> str: 86 return "<< " + " < ".join(map(str, self)) + " <<" 87 88 def push(self, *ds: D) -> None: 89 """Push data onto `FIFOQueue`. 90 91 * like a Python List, does not return a value 92 93 """ 94 self._ca.pushR(*ds) 95 96 def pop(self) -> MB[D]: 97 """Pop data from `FIFOQueue`. 98 99 * pop item off queue, return item in a maybe monad 100 * returns an empty `MB()` if queue is empty 101 102 """ 103 if self._ca: 104 return MB(self._ca.popL()) 105 else: 106 return MB() 107 108 def peak_last_in(self) -> MB[D]: 109 """Peak last data into `FIFOQueue`. 110 111 * return a maybe monad of the last item pushed to queue 112 * does not consume the data 113 * if item already popped, return `MB()` 114 115 """ 116 if self._ca: 117 return MB(self._ca[-1]) 118 else: 119 return MB() 120 121 def peak_next_out(self) -> MB[D]: 122 """Peak next data out of `FIFOQueue`. 123 124 * returns a maybe monad of the next item to be popped from the queue. 125 * does not consume it the item 126 * returns `MB()` if queue is empty 127 128 """ 129 if self._ca: 130 return MB(self._ca[0]) 131 else: 132 return MB() 133 134 def fold[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 135 """Fold `FIFOQueue` in natural order. 136 137 Reduce with `f` using an optional initial value. 138 139 * folds in natural FIFO Order (oldest to newest) 140 * note that when an initial value is not given then `~L = ~D` 141 * if iterable empty & no initial value given, return `MB()` 142 * traditional FP type order given for function `f` 143 144 """ 145 if initial is None: 146 if not self._ca: 147 return MB() 148 return MB(self._ca.foldL(f, initial=initial)) 149 150 def map[U](self, f: Callable[[D], U]) -> FIFOQueue[U]: 151 """Map over the `FIFOQueue`. 152 153 * map function `f` over the queue 154 * oldest to newest 155 * retain original order 156 * returns a new instance 157 158 """ 159 return FIFOQueue(*map(f, self._ca))
FIFO Queue
- stateful First-In-First-Out (FIFO) data structure
- initial data pushed on in natural FIFO order
81 def copy(self) -> FIFOQueue[D]: 82 """Return a shallow copy of the `FIFOQueue`.""" 83 return FIFOQueue(*self._ca)
Return a shallow copy of the FIFOQueue
.
88 def push(self, *ds: D) -> None: 89 """Push data onto `FIFOQueue`. 90 91 * like a Python List, does not return a value 92 93 """ 94 self._ca.pushR(*ds)
Push data onto FIFOQueue
.
- like a Python List, does not return a value
96 def pop(self) -> MB[D]: 97 """Pop data from `FIFOQueue`. 98 99 * pop item off queue, return item in a maybe monad 100 * returns an empty `MB()` if queue is empty 101 102 """ 103 if self._ca: 104 return MB(self._ca.popL()) 105 else: 106 return MB()
Pop data from FIFOQueue
.
- pop item off queue, return item in a maybe monad
- returns an empty
MB()
if queue is empty
108 def peak_last_in(self) -> MB[D]: 109 """Peak last data into `FIFOQueue`. 110 111 * return a maybe monad of the last item pushed to queue 112 * does not consume the data 113 * if item already popped, return `MB()` 114 115 """ 116 if self._ca: 117 return MB(self._ca[-1]) 118 else: 119 return MB()
Peak last data into FIFOQueue
.
- return a maybe monad of the last item pushed to queue
- does not consume the data
- if item already popped, return
MB()
121 def peak_next_out(self) -> MB[D]: 122 """Peak next data out of `FIFOQueue`. 123 124 * returns a maybe monad of the next item to be popped from the queue. 125 * does not consume it the item 126 * returns `MB()` if queue is empty 127 128 """ 129 if self._ca: 130 return MB(self._ca[0]) 131 else: 132 return MB()
Peak next data out of FIFOQueue
.
- returns a maybe monad of the next item to be popped from the queue.
- does not consume it the item
- returns
MB()
if queue is empty
134 def fold[L](self, f: Callable[[L, D], L], initial: Optional[L]=None) -> MB[L]: 135 """Fold `FIFOQueue` in natural order. 136 137 Reduce with `f` using an optional initial value. 138 139 * folds in natural FIFO Order (oldest to newest) 140 * note that when an initial value is not given then `~L = ~D` 141 * if iterable empty & no initial value given, return `MB()` 142 * traditional FP type order given for function `f` 143 144 """ 145 if initial is None: 146 if not self._ca: 147 return MB() 148 return MB(self._ca.foldL(f, initial=initial))
Fold FIFOQueue
in natural order.
Reduce with f
using an optional initial value.
- folds in natural FIFO Order (oldest to newest)
- note that when an initial value is not given then
~L = ~D
- if iterable empty & no initial value given, return
MB()
- traditional FP type order given for function
f
150 def map[U](self, f: Callable[[D], U]) -> FIFOQueue[U]: 151 """Map over the `FIFOQueue`. 152 153 * map function `f` over the queue 154 * oldest to newest 155 * retain original order 156 * returns a new instance 157 158 """ 159 return FIFOQueue(*map(f, self._ca))
Map over the FIFOQueue
.
- map function
f
over the queue- oldest to newest
- retain original order
- returns a new instance
161class LIFOQueue[D](QueueBase[D]): 162 """#### LIFO Queue 163 164 * stateful Last-In-First-Out (LIFO) data structure 165 * initial data pushed on in natural LIFO order 166 167 """ 168 __slots__ = () 169 170 def __iter__(self) -> Iterator[D]: 171 return reversed(list(self._ca)) 172 173 def __str__(self) -> str: 174 return "|| " + " > ".join(map(str, self)) + " ><" 175 176 def copy(self) -> LIFOQueue[D]: 177 """Return a shallow copy of the `LIFOQueue`.""" 178 return LIFOQueue(*reversed(self._ca)) 179 180 def push(self, *ds: D) -> None: 181 """Push data onto `LIFOQueue`. 182 183 * like a Python List, does not return a value 184 185 """ 186 self._ca.pushR(*ds) 187 188 def pop(self) -> MB[D]: 189 """Pop data from `LIFOQueue`. 190 191 * pop item off of queue, return item in a maybe monad 192 * returns an empty `MB()` if queue is empty 193 194 """ 195 if self._ca: 196 return MB(self._ca.popR()) 197 else: 198 return MB() 199 200 def peak(self) -> MB[D]: 201 """Peak next data out of `LIFOQueue`. 202 203 * return a maybe monad of the next item to be popped from the queue 204 * does not consume the item 205 * returns `MB()` if queue is empty 206 207 """ 208 if self._ca: 209 return MB(self._ca[-1]) 210 else: 211 return MB() 212 213 def fold[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 214 """Fold `LIFOQueue` in natural order. 215 216 Reduce with `f` using an optional initial value. 217 218 * folds in natural LIFO Order (newest to oldest) 219 * note that when an initial value is not given then `~R = ~D` 220 * if iterable empty & no initial value given, return `MB()` 221 * traditional FP type order given for function `f` 222 223 """ 224 if initial is None: 225 if not self._ca: 226 return MB() 227 return MB(self._ca.foldR(f, initial=initial)) 228 229 def map[U](self, f: Callable[[D], U]) -> LIFOQueue[U]: 230 """Map Over the `LIFOQueue`. 231 232 * map the function `f` over the queue 233 * newest to oldest 234 * retain original order 235 * returns a new instance 236 237 """ 238 return LIFOQueue(*reversed(CA(*map(f, reversed(self._ca)))))
LIFO Queue
- stateful Last-In-First-Out (LIFO) data structure
- initial data pushed on in natural LIFO order
176 def copy(self) -> LIFOQueue[D]: 177 """Return a shallow copy of the `LIFOQueue`.""" 178 return LIFOQueue(*reversed(self._ca))
Return a shallow copy of the LIFOQueue
.
180 def push(self, *ds: D) -> None: 181 """Push data onto `LIFOQueue`. 182 183 * like a Python List, does not return a value 184 185 """ 186 self._ca.pushR(*ds)
Push data onto LIFOQueue
.
- like a Python List, does not return a value
188 def pop(self) -> MB[D]: 189 """Pop data from `LIFOQueue`. 190 191 * pop item off of queue, return item in a maybe monad 192 * returns an empty `MB()` if queue is empty 193 194 """ 195 if self._ca: 196 return MB(self._ca.popR()) 197 else: 198 return MB()
Pop data from LIFOQueue
.
- pop item off of queue, return item in a maybe monad
- returns an empty
MB()
if queue is empty
200 def peak(self) -> MB[D]: 201 """Peak next data out of `LIFOQueue`. 202 203 * return a maybe monad of the next item to be popped from the queue 204 * does not consume the item 205 * returns `MB()` if queue is empty 206 207 """ 208 if self._ca: 209 return MB(self._ca[-1]) 210 else: 211 return MB()
Peak next data out of LIFOQueue
.
- return a maybe monad of the next item to be popped from the queue
- does not consume the item
- returns
MB()
if queue is empty
213 def fold[R](self, f: Callable[[D, R], R], initial: Optional[R]=None) -> MB[R]: 214 """Fold `LIFOQueue` in natural order. 215 216 Reduce with `f` using an optional initial value. 217 218 * folds in natural LIFO Order (newest to oldest) 219 * note that when an initial value is not given then `~R = ~D` 220 * if iterable empty & no initial value given, return `MB()` 221 * traditional FP type order given for function `f` 222 223 """ 224 if initial is None: 225 if not self._ca: 226 return MB() 227 return MB(self._ca.foldR(f, initial=initial))
Fold LIFOQueue
in natural order.
Reduce with f
using an optional initial value.
- folds in natural LIFO Order (newest to oldest)
- note that when an initial value is not given then
~R = ~D
- if iterable empty & no initial value given, return
MB()
- traditional FP type order given for function
f
229 def map[U](self, f: Callable[[D], U]) -> LIFOQueue[U]: 230 """Map Over the `LIFOQueue`. 231 232 * map the function `f` over the queue 233 * newest to oldest 234 * retain original order 235 * returns a new instance 236 237 """ 238 return LIFOQueue(*reversed(CA(*map(f, reversed(self._ca)))))
Map Over the LIFOQueue
.
- map the function
f
over the queue- newest to oldest
- retain original order
- returns a new instance
39class QueueBase[D](): 40 """#### Base class for circular area based queues. 41 42 * primarily for DRY inheritance 43 * implemented with a grscheller.circular-array (has-a) 44 * order of initial data retained 45 46 """ 47 __slots__ = '_ca' 48 49 def __init__(self, *ds: D): 50 self._ca = CA(*ds) 51 52 def __repr__(self) -> str: 53 if len(self) == 0: 54 return type(self).__name__ + '()' 55 else: 56 return type(self).__name__ + '(' + ', '.join(map(repr, self._ca)) + ')' 57 58 def __bool__(self) -> bool: 59 return len(self._ca) > 0 60 61 def __len__(self) -> int: 62 return len(self._ca) 63 64 def __eq__(self, other: object) -> bool: 65 if not isinstance(other, type(self)): 66 return False 67 return self._ca == other._ca
Base class for circular area based queues.
- primarily for DRY inheritance
- implemented with a grscheller.circular-array (has-a)
- order of initial data retained