63 lines
1.6 KiB
Python
63 lines
1.6 KiB
Python
from dataclasses import dataclass
|
|
from typing import Any, Callable, Optional, TypeVar, cast
|
|
|
|
from reactivex import Observable, operators, typing
|
|
|
|
_T = TypeVar("_T")
|
|
|
|
|
|
@dataclass
|
|
class AverageValue:
|
|
sum: float
|
|
count: int
|
|
|
|
|
|
def average_(
|
|
key_mapper: Optional[typing.Mapper[_T, float]] = None,
|
|
) -> Callable[[Observable[_T]], Observable[float]]:
|
|
def average(source: Observable[Any]) -> Observable[float]:
|
|
"""Partially applied average operator.
|
|
|
|
Computes the average of an observable sequence of values that
|
|
are in the sequence or obtained by invoking a transform
|
|
function on each element of the input sequence if present.
|
|
|
|
Examples:
|
|
>>> res = average(source)
|
|
|
|
Args:
|
|
source: Source observable to average.
|
|
|
|
Returns:
|
|
An observable sequence containing a single element with the
|
|
average of the sequence of values.
|
|
"""
|
|
|
|
key_mapper_: typing.Mapper[_T, float] = key_mapper or (
|
|
lambda x: float(cast(Any, x))
|
|
)
|
|
|
|
def accumulator(prev: AverageValue, cur: float) -> AverageValue:
|
|
return AverageValue(sum=prev.sum + cur, count=prev.count + 1)
|
|
|
|
def mapper(s: AverageValue) -> float:
|
|
if s.count == 0:
|
|
raise Exception("The input sequence was empty")
|
|
|
|
return s.sum / float(s.count)
|
|
|
|
seed = AverageValue(sum=0, count=0)
|
|
|
|
ret = source.pipe(
|
|
operators.map(key_mapper_),
|
|
operators.scan(accumulator, seed),
|
|
operators.last(),
|
|
operators.map(mapper),
|
|
)
|
|
return ret
|
|
|
|
return average
|
|
|
|
|
|
__all__ = ["average_"]
|