Refactored cpl-query Iterable & Enumerable #129
This commit is contained in:
@@ -1,10 +1,19 @@
|
||||
from abc import abstractmethod, ABC
|
||||
from typing import Optional, Callable, Union
|
||||
|
||||
from cpl_query._helper import is_number
|
||||
from cpl_query.base.sequence_abc import SequenceABC
|
||||
from cpl_query.exceptions import InvalidTypeException, ArgumentNoneException, ExceptionArgument, IndexOutOfRangeException
|
||||
|
||||
class QueryableABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def _default_lambda(x: object):
|
||||
return x
|
||||
|
||||
|
||||
class QueryableABC(SequenceABC):
|
||||
|
||||
def __init__(self, t: type = None, values: list = None):
|
||||
SequenceABC.__init__(self, t, values)
|
||||
|
||||
def all(self, _func: Callable = None) -> bool:
|
||||
r"""Checks if every element of list equals result found by function
|
||||
|
||||
@@ -17,9 +26,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
bool
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
return self.count(_func) == self.count()
|
||||
|
||||
@abstractmethod
|
||||
def any(self, _func: Callable = None) -> bool:
|
||||
r"""Checks if list contains result found by function
|
||||
|
||||
@@ -32,9 +43,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
bool
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
return self.where(_func).count() > 0
|
||||
|
||||
@abstractmethod
|
||||
def average(self, _func: Callable = None) -> Union[int, float, complex]:
|
||||
r"""Returns average value of list
|
||||
|
||||
@@ -47,10 +60,12 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Union[int, float, complex]
|
||||
"""
|
||||
pass
|
||||
if _func is None and not is_number(self.type):
|
||||
raise InvalidTypeException()
|
||||
|
||||
@abstractmethod
|
||||
def contains(self, value: object) -> bool:
|
||||
return self.sum(_func) / self.count()
|
||||
|
||||
def contains(self, _value: object) -> bool:
|
||||
r"""Checks if list contains value given by function
|
||||
|
||||
Parameter
|
||||
@@ -62,9 +77,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
bool
|
||||
"""
|
||||
pass
|
||||
if _value is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.value)
|
||||
|
||||
return self.where(lambda x: x == _value).count() > 0
|
||||
|
||||
@abstractmethod
|
||||
def count(self, _func: Callable = None) -> int:
|
||||
r"""Returns length of list or count of found elements
|
||||
|
||||
@@ -77,9 +94,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
int
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
return self.__len__()
|
||||
|
||||
return self.where(_func).__len__()
|
||||
|
||||
@abstractmethod
|
||||
def distinct(self, _func: Callable = None) -> 'QueryableABC':
|
||||
r"""Returns list without redundancies
|
||||
|
||||
@@ -92,39 +111,62 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
@abstractmethod
|
||||
def element_at(self, index: int) -> any:
|
||||
result = []
|
||||
known_values = []
|
||||
for element in self:
|
||||
value = _func(element)
|
||||
if value in known_values:
|
||||
continue
|
||||
|
||||
known_values.append(value)
|
||||
result.append(element)
|
||||
|
||||
return type(self)(self._type, result)
|
||||
|
||||
def element_at(self, _index: int) -> any:
|
||||
r"""Returns element at given index
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
Value at index: any
|
||||
Value at _index: any
|
||||
"""
|
||||
pass
|
||||
if _index is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.index)
|
||||
|
||||
@abstractmethod
|
||||
def element_at_or_default(self, index: int) -> Optional[any]:
|
||||
result = self[_index]
|
||||
if result is None:
|
||||
raise IndexOutOfRangeException
|
||||
|
||||
return result
|
||||
|
||||
def element_at_or_default(self, _index: int) -> Optional[any]:
|
||||
r"""Returns element at given index or None
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
Value at index: Optional[any]
|
||||
Value at _index: Optional[any]
|
||||
"""
|
||||
pass
|
||||
if _index is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.index)
|
||||
|
||||
try:
|
||||
return self[_index]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@abstractmethod
|
||||
def first(self) -> any:
|
||||
r"""Returns first element
|
||||
|
||||
@@ -132,9 +174,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
First element of list: any
|
||||
"""
|
||||
pass
|
||||
if len(self) == 0:
|
||||
raise IndexOutOfRangeException()
|
||||
|
||||
return self[0]
|
||||
|
||||
@abstractmethod
|
||||
def first_or_default(self) -> any:
|
||||
r"""Returns first element or None
|
||||
|
||||
@@ -142,9 +186,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
First element of list: Optional[any]
|
||||
"""
|
||||
pass
|
||||
if len(self) == 0:
|
||||
return None
|
||||
|
||||
return self[0]
|
||||
|
||||
@abstractmethod
|
||||
def for_each(self, _func: Callable = None):
|
||||
r"""Runs given function for each element of list
|
||||
|
||||
@@ -153,7 +199,11 @@ class QueryableABC(ABC):
|
||||
func: :class: `Callable`
|
||||
function to call
|
||||
"""
|
||||
pass
|
||||
if _func is not None:
|
||||
for element in self:
|
||||
_func(element)
|
||||
|
||||
return self
|
||||
|
||||
def group_by(self, _func: Callable = None) -> 'QueryableABC':
|
||||
r"""Groups by func
|
||||
@@ -162,9 +212,23 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Grouped list[list[any]]: any
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
groups = {}
|
||||
|
||||
for v in self:
|
||||
value = _func(v)
|
||||
if v not in groups:
|
||||
groups[value] = []
|
||||
|
||||
groups[value].append(v)
|
||||
|
||||
v = []
|
||||
for g in groups.values():
|
||||
v.append(type(self)(None, g))
|
||||
x = type(self)(type(self), v)
|
||||
return x
|
||||
|
||||
@abstractmethod
|
||||
def last(self) -> any:
|
||||
r"""Returns last element
|
||||
|
||||
@@ -172,9 +236,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Last element of list: any
|
||||
"""
|
||||
pass
|
||||
if len(self) == 0:
|
||||
raise IndexOutOfRangeException()
|
||||
|
||||
return self[len(self) - 1]
|
||||
|
||||
@abstractmethod
|
||||
def last_or_default(self) -> any:
|
||||
r"""Returns last element or None
|
||||
|
||||
@@ -182,9 +248,11 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Last element of list: Optional[any]
|
||||
"""
|
||||
pass
|
||||
if len(self) == 0:
|
||||
return None
|
||||
|
||||
return self[len(self) - 1]
|
||||
|
||||
@abstractmethod
|
||||
def max(self, _func: Callable = None) -> Union[int, float, complex]:
|
||||
r"""Returns the highest value
|
||||
|
||||
@@ -197,19 +265,33 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Union[int, float, complex]
|
||||
"""
|
||||
pass
|
||||
if _func is None and not is_number(self.type):
|
||||
raise InvalidTypeException()
|
||||
|
||||
@abstractmethod
|
||||
def median(self) -> Union[int, float]:
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
return _func(max(self, key=_func))
|
||||
|
||||
def median(self, _func=None) -> Union[int, float]:
|
||||
r"""Return the median value of data elements
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[int, float]
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
result = self.order_by(_func).select(_func).to_list()
|
||||
length = len(result)
|
||||
i = int(length / 2)
|
||||
return (
|
||||
result[i]
|
||||
if length % 2 == 1
|
||||
else (float(result[i - 1]) + float(result[i])) / float(2)
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def min(self, _func: Callable = None) -> Union[int, float, complex]:
|
||||
r"""Returns the lowest value
|
||||
|
||||
@@ -222,9 +304,14 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Union[int, float, complex]
|
||||
"""
|
||||
pass
|
||||
if _func is None and not is_number(self.type):
|
||||
raise InvalidTypeException()
|
||||
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
return _func(min(self, key=_func))
|
||||
|
||||
@abstractmethod
|
||||
def order_by(self, _func: Callable = None) -> 'QueryableABC':
|
||||
r"""Sorts elements by function in ascending order
|
||||
|
||||
@@ -237,9 +324,12 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
from cpl_query.base.ordered_queryable import OrderedQueryable
|
||||
return OrderedQueryable(self.type, sorted(self, key=_func), _func)
|
||||
|
||||
@abstractmethod
|
||||
def order_by_descending(self, _func: Callable = None) -> 'QueryableABC':
|
||||
r"""Sorts elements by function in descending order
|
||||
|
||||
@@ -252,9 +342,12 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
from cpl_query.base.ordered_queryable import OrderedQueryable
|
||||
return OrderedQueryable(self.type, sorted(self, key=_func, reverse=True), _func)
|
||||
|
||||
@abstractmethod
|
||||
def reverse(self) -> 'QueryableABC':
|
||||
r"""Reverses list
|
||||
|
||||
@@ -262,29 +355,31 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
return type(self)(self._type, list(reversed(self)))
|
||||
|
||||
@abstractmethod
|
||||
def select(self, _f: Callable) -> 'QueryableABC':
|
||||
def select(self, _func: Callable) -> 'QueryableABC':
|
||||
r"""Formats each element of list to a given format
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
@abstractmethod
|
||||
def select_many(self, _f: Callable) -> 'QueryableABC':
|
||||
return type(self)(any, [_func(_o) for _o in self])
|
||||
|
||||
def select_many(self, _func: Callable) -> 'QueryableABC':
|
||||
r"""Flattens resulting lists to one
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
# The line below is pain. I don't understand anything of it...
|
||||
# written on 09.11.2022 by Sven Heidemann
|
||||
return type(self)(any, [_a for _o in self for _a in _func(_o)])
|
||||
|
||||
@abstractmethod
|
||||
def single(self) -> any:
|
||||
r"""Returns one single element of list
|
||||
|
||||
@@ -297,9 +392,13 @@ class QueryableABC(ABC):
|
||||
ArgumentNoneException: when argument is None
|
||||
Exception: when argument is None or found more than one element
|
||||
"""
|
||||
pass
|
||||
if len(self) > 1:
|
||||
raise Exception('Found more than one element')
|
||||
elif len(self) == 0:
|
||||
raise Exception('Found no element')
|
||||
|
||||
return self[0]
|
||||
|
||||
@abstractmethod
|
||||
def single_or_default(self) -> Optional[any]:
|
||||
r"""Returns one single element of list
|
||||
|
||||
@@ -307,39 +406,48 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Found value: Optional[any]
|
||||
"""
|
||||
pass
|
||||
if len(self) > 1:
|
||||
raise Exception('Index out of range')
|
||||
elif len(self) == 0:
|
||||
return None
|
||||
|
||||
@abstractmethod
|
||||
def skip(self, index: int) -> 'QueryableABC':
|
||||
return self[0]
|
||||
|
||||
def skip(self, _index: int) -> 'QueryableABC':
|
||||
r"""Skips all elements from index
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _index is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.index)
|
||||
|
||||
@abstractmethod
|
||||
def skip_last(self, index: int) -> 'QueryableABC':
|
||||
return type(self)(self.type, values=self[_index:])
|
||||
|
||||
def skip_last(self, _index: int) -> 'QueryableABC':
|
||||
r"""Skips all elements after index
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _index is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.index)
|
||||
|
||||
index = len(self) - _index
|
||||
return type(self)(self._type, self[:index])
|
||||
|
||||
@abstractmethod
|
||||
def sum(self, _func: Callable = None) -> Union[int, float, complex]:
|
||||
r"""Sum of all values
|
||||
|
||||
@@ -352,39 +460,54 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
Union[int, float, complex]
|
||||
"""
|
||||
pass
|
||||
if _func is None and not is_number(self.type):
|
||||
raise InvalidTypeException()
|
||||
|
||||
@abstractmethod
|
||||
def take(self, index: int) -> 'QueryableABC':
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
result = 0
|
||||
for x in self:
|
||||
result += _func(x)
|
||||
|
||||
return result
|
||||
|
||||
def take(self, _index: int) -> 'QueryableABC':
|
||||
r"""Takes all elements from index
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _index is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.index)
|
||||
|
||||
@abstractmethod
|
||||
def take_last(self, index: int) -> 'QueryableABC':
|
||||
return type(self)(self._type, self[:_index])
|
||||
|
||||
def take_last(self, _index: int) -> 'QueryableABC':
|
||||
r"""Takes all elements after index
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index: :class:`int`
|
||||
_index: :class:`int`
|
||||
index
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
index = len(self) - _index
|
||||
|
||||
if index >= len(self) or index < 0:
|
||||
raise IndexOutOfRangeException()
|
||||
|
||||
return type(self)(self._type, self[index:])
|
||||
|
||||
@abstractmethod
|
||||
def where(self, _func: Callable = None) -> 'QueryableABC':
|
||||
r"""Select element by function
|
||||
|
||||
@@ -397,4 +520,15 @@ class QueryableABC(ABC):
|
||||
-------
|
||||
:class: `cpl_query.base.queryable_abc.QueryableABC`
|
||||
"""
|
||||
pass
|
||||
if _func is None:
|
||||
raise ArgumentNoneException(ExceptionArgument.func)
|
||||
|
||||
if _func is None:
|
||||
_func = _default_lambda
|
||||
|
||||
result = []
|
||||
for element in self:
|
||||
if _func(element):
|
||||
result.append(element)
|
||||
|
||||
return type(self)(self.type, result)
|
||||
|
||||
Reference in New Issue
Block a user