- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1380 lines
37 KiB
Python
1380 lines
37 KiB
Python
"""
|
|
Java java.util.stream standard library APIs implemented in Python.
|
|
java.util.stream package - Stream, IntStream, LongStream, DoubleStream, Collectors, etc.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .._core import Stub
|
|
from ..java.util import Optional, NoSuchElementException
|
|
from ..java.lang import RuntimeException
|
|
import typing as _typing
|
|
import itertools as _itertools
|
|
import functools as _functools
|
|
import math as _py_math
|
|
|
|
__all__ = [
|
|
"Stream", "IntStream", "LongStream", "DoubleStream",
|
|
"Collector", "Collectors", "StreamSupport",
|
|
"BaseStream", "Sink", "TerminalOp", "TerminalSink",
|
|
"AbstractPipeline", "ReferencePipeline",
|
|
"IntPipeline", "LongPipeline", "DoublePipeline",
|
|
"SliceOps", "WhileOps", "DistinctOps", "SortedOps",
|
|
"FindOps", "MatchOps", "ReduceOps", "ForEachOps",
|
|
"MapOps", "FilterOps", "FlatMapOps", "PeekOps",
|
|
]
|
|
|
|
T = _typing.TypeVar("T")
|
|
R = _typing.TypeVar("R")
|
|
A = _typing.TypeVar("A")
|
|
|
|
|
|
# ============================================================
|
|
# BaseStream
|
|
# ============================================================
|
|
|
|
class BaseStream(Stub):
|
|
"""java.util.stream.BaseStream"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._closed = False
|
|
self._parallel = False
|
|
|
|
def iterator(self):
|
|
raise NotImplementedError
|
|
|
|
def spliterator(self):
|
|
raise NotImplementedError
|
|
|
|
def isParallel(self):
|
|
return self._parallel
|
|
|
|
def sequential(self):
|
|
self._parallel = False
|
|
return self
|
|
|
|
def parallel(self):
|
|
self._parallel = True
|
|
return self
|
|
|
|
def unordered(self):
|
|
return self
|
|
|
|
def onClose(self, close_handler):
|
|
return self
|
|
|
|
def close(self):
|
|
self._closed = True
|
|
|
|
|
|
# ============================================================
|
|
# Builder
|
|
# ============================================================
|
|
|
|
class StreamBuilder(Stub):
|
|
"""java.util.stream.Stream.Builder"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._elements = []
|
|
|
|
def accept(self, t):
|
|
self._elements.append(t)
|
|
|
|
def add(self, t):
|
|
self._elements.append(t)
|
|
return self
|
|
|
|
def build(self):
|
|
return Stream(self._elements[:])
|
|
|
|
def toString(self):
|
|
return "Stream.Builder"
|
|
|
|
|
|
class IntStreamBuilder(Stub):
|
|
"""java.util.stream.IntStream.Builder"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._elements = []
|
|
|
|
def accept(self, t):
|
|
self._elements.append(int(t))
|
|
|
|
def add(self, t):
|
|
self._elements.append(int(t))
|
|
return self
|
|
|
|
def build(self):
|
|
return IntStream(self._elements[:])
|
|
|
|
|
|
class LongStreamBuilder(Stub):
|
|
"""java.util.stream.LongStream.Builder"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._elements = []
|
|
|
|
def accept(self, t):
|
|
self._elements.append(int(t))
|
|
|
|
def add(self, t):
|
|
self._elements.append(int(t))
|
|
return self
|
|
|
|
def build(self):
|
|
return LongStream(self._elements[:])
|
|
|
|
|
|
class DoubleStreamBuilder(Stub):
|
|
"""java.util.stream.DoubleStream.Builder"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._elements = []
|
|
|
|
def accept(self, t):
|
|
self._elements.append(float(t))
|
|
|
|
def add(self, t):
|
|
self._elements.append(float(t))
|
|
return self
|
|
|
|
def build(self):
|
|
return DoubleStream(self._elements[:])
|
|
|
|
|
|
# ============================================================
|
|
# Stream
|
|
# ============================================================
|
|
|
|
class Stream(BaseStream):
|
|
"""java.util.stream.Stream"""
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = list(data) if data is not None else []
|
|
self._intermediate_ops = []
|
|
|
|
def filter(self, predicate):
|
|
result = [x for x in self._get_data() if predicate.test(x)]
|
|
return Stream(result)
|
|
|
|
def map(self, mapper):
|
|
result = [mapper.apply(x) for x in self._get_data()]
|
|
return Stream(result)
|
|
|
|
def mapToInt(self, mapper):
|
|
result = [mapper.applyAsInt(x) for x in self._get_data()]
|
|
return IntStream(result)
|
|
|
|
def mapToLong(self, mapper):
|
|
result = [mapper.applyAsLong(x) for x in self._get_data()]
|
|
return LongStream(result)
|
|
|
|
def mapToDouble(self, mapper):
|
|
result = [mapper.applyAsDouble(x) for x in self._get_data()]
|
|
return DoubleStream(result)
|
|
|
|
def flatMap(self, mapper):
|
|
results = []
|
|
for x in self._get_data():
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, Stream):
|
|
results.extend(stream._get_data())
|
|
elif hasattr(stream, '__iter__'):
|
|
results.extend(stream)
|
|
return Stream(results)
|
|
|
|
def distinct(self):
|
|
seen = set()
|
|
result = []
|
|
for x in self._get_data():
|
|
if x not in seen:
|
|
seen.add(x)
|
|
result.append(x)
|
|
return Stream(result)
|
|
|
|
def sorted(self, comparator=None):
|
|
result = list(self._get_data())
|
|
if comparator:
|
|
from functools import cmp_to_key
|
|
result.sort(key=cmp_to_key(
|
|
lambda a, b: comparator.compare(a, b)
|
|
))
|
|
else:
|
|
result.sort()
|
|
return Stream(result)
|
|
|
|
def peek(self, action):
|
|
for x in self._get_data():
|
|
action.accept(x)
|
|
return Stream(self._get_data())
|
|
|
|
def limit(self, max_size):
|
|
return Stream(self._get_data()[:max_size])
|
|
|
|
def skip(self, n):
|
|
return Stream(self._get_data()[n:])
|
|
|
|
def forEach(self, action):
|
|
for x in self._get_data():
|
|
action.accept(x)
|
|
|
|
def forEachOrdered(self, action):
|
|
self.forEach(action)
|
|
|
|
def toArray(self, generator=None):
|
|
data = self._get_data()
|
|
if generator is not None:
|
|
arr = generator.apply(len(data))
|
|
for i, x in enumerate(data):
|
|
arr[i] = x
|
|
return arr
|
|
return list(data)
|
|
|
|
def reduce(self, identity_or_accumulator, accumulator=None, combiner=None):
|
|
data = self._get_data()
|
|
if accumulator is None:
|
|
# reduce(BinaryOperator)
|
|
acc = identity_or_accumulator
|
|
if not data:
|
|
return Optional.empty()
|
|
result = data[0]
|
|
for x in data[1:]:
|
|
result = acc.apply(result, x)
|
|
return Optional.of(result)
|
|
else:
|
|
# reduce(identity, accumulator)
|
|
result = identity_or_accumulator
|
|
for x in data:
|
|
result = accumulator.apply(result, x)
|
|
if combiner:
|
|
result = combiner.apply(result, result)
|
|
return result
|
|
|
|
def collect(self, supplier_or_collector, accumulator=None, combiner=None):
|
|
data = self._get_data()
|
|
if accumulator is None:
|
|
return supplier_or_collector # Collector
|
|
container = supplier_or_collector.get()
|
|
for x in data:
|
|
accumulator.accept(container, x)
|
|
return container
|
|
|
|
def min(self, comparator):
|
|
data = self._get_data()
|
|
if not data:
|
|
return Optional.empty()
|
|
return Optional.of(min(data, key=_functools.cmp_to_key(
|
|
lambda a, b: comparator.compare(a, b)
|
|
)))
|
|
|
|
def max(self, comparator):
|
|
data = self._get_data()
|
|
if not data:
|
|
return Optional.empty()
|
|
return Optional.of(max(data, key=_functools.cmp_to_key(
|
|
lambda a, b: comparator.compare(a, b)
|
|
)))
|
|
|
|
def count(self):
|
|
return len(self._get_data())
|
|
|
|
def anyMatch(self, predicate):
|
|
return any(predicate.test(x) for x in self._get_data())
|
|
|
|
def allMatch(self, predicate):
|
|
return all(predicate.test(x) for x in self._get_data())
|
|
|
|
def noneMatch(self, predicate):
|
|
return not any(predicate.test(x) for x in self._get_data())
|
|
|
|
def findFirst(self):
|
|
data = self._get_data()
|
|
if data:
|
|
return Optional.of(data[0])
|
|
return Optional.empty()
|
|
|
|
def findAny(self):
|
|
data = self._get_data()
|
|
if data:
|
|
return Optional.of(data[0])
|
|
return Optional.empty()
|
|
|
|
def flatMapToInt(self, mapper):
|
|
results = []
|
|
for x in self._get_data():
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, IntStream):
|
|
results.extend(stream._get_data())
|
|
return IntStream(results)
|
|
|
|
def flatMapToLong(self, mapper):
|
|
results = []
|
|
for x in self._get_data():
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, LongStream):
|
|
results.extend(stream._get_data())
|
|
return LongStream(results)
|
|
|
|
def flatMapToDouble(self, mapper):
|
|
results = []
|
|
for x in self._get_data():
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, DoubleStream):
|
|
results.extend(stream._get_data())
|
|
return DoubleStream(results)
|
|
|
|
def iterator(self):
|
|
return iter(self._get_data())
|
|
|
|
def spliterator(self):
|
|
return Spliterator(self._get_data())
|
|
|
|
def isParallel(self):
|
|
return self._parallel
|
|
|
|
def _get_data(self):
|
|
return self._data
|
|
|
|
@staticmethod
|
|
def of(*args):
|
|
return Stream(list(args))
|
|
|
|
@staticmethod
|
|
def empty():
|
|
return Stream([])
|
|
|
|
@staticmethod
|
|
def concat(a, b):
|
|
return Stream(list(a._get_data()) + list(b._get_data()))
|
|
|
|
@staticmethod
|
|
def generate(supplier):
|
|
return Stream([])
|
|
|
|
@staticmethod
|
|
def iterate(seed, has_next_or_predicate, next_fn=None):
|
|
if next_fn is None:
|
|
fn = seed
|
|
return Stream([])
|
|
result = []
|
|
current = seed
|
|
while has_next_or_predicate.test(current):
|
|
result.append(current)
|
|
current = next_fn.apply(current)
|
|
return Stream(result)
|
|
|
|
# Nested Builder class
|
|
class Builder:
|
|
def __init__(self):
|
|
self._impl = StreamBuilder()
|
|
|
|
def accept(self, t):
|
|
self._impl.accept(t)
|
|
|
|
def add(self, t):
|
|
self._impl.add(t)
|
|
return self
|
|
|
|
def build(self):
|
|
return self._impl.build()
|
|
|
|
|
|
# ============================================================
|
|
# IntStream
|
|
# ============================================================
|
|
|
|
class IntStream(BaseStream):
|
|
"""java.util.stream.IntStream"""
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = [int(x) for x in (data or [])]
|
|
|
|
def filter(self, predicate):
|
|
return IntStream([x for x in self._data if predicate.test(x)])
|
|
|
|
def map(self, mapper):
|
|
return IntStream([mapper.applyAsInt(x) for x in self._data])
|
|
|
|
def mapToObj(self, mapper):
|
|
return Stream([mapper.apply(x) for x in self._data])
|
|
|
|
def mapToLong(self, mapper):
|
|
return LongStream([mapper.applyAsLong(x) for x in self._data])
|
|
|
|
def mapToDouble(self, mapper):
|
|
return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
|
|
|
|
def flatMap(self, mapper):
|
|
results = []
|
|
for x in self._data:
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, IntStream):
|
|
results.extend(stream._data)
|
|
return IntStream(results)
|
|
|
|
def distinct(self):
|
|
return IntStream(list(set(self._data)))
|
|
|
|
def sorted(self):
|
|
return IntStream(sorted(self._data))
|
|
|
|
def peek(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
return IntStream(self._data[:])
|
|
|
|
def limit(self, max_size):
|
|
return IntStream(self._data[:max_size])
|
|
|
|
def skip(self, n):
|
|
return IntStream(self._data[n:])
|
|
|
|
def forEach(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
|
|
def forEachOrdered(self, action):
|
|
self.forEach(action)
|
|
|
|
def toArray(self):
|
|
return list(self._data)
|
|
|
|
def reduce(self, identity_or_op, op=None):
|
|
if op is None:
|
|
if not self._data:
|
|
return Optional.empty()
|
|
result = self._data[0]
|
|
for x in self._data[1:]:
|
|
result = identity_or_op.applyAsInt(result, x)
|
|
return Optional.of(result)
|
|
result = identity_or_op
|
|
for x in self._data:
|
|
result = op.applyAsInt(result, x)
|
|
return result
|
|
|
|
def collect(self, supplier, accumulator, combiner):
|
|
container = supplier.get()
|
|
for x in self._data:
|
|
accumulator.accept(container, x)
|
|
return container
|
|
|
|
def sum(self):
|
|
return sum(self._data)
|
|
|
|
def min(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(min(self._data))
|
|
|
|
def max(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(max(self._data))
|
|
|
|
def count(self):
|
|
return len(self._data)
|
|
|
|
def average(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(sum(self._data) / len(self._data))
|
|
|
|
def summaryStatistics(self):
|
|
return IntSummaryStatistics(self._data)
|
|
|
|
def anyMatch(self, predicate):
|
|
return any(predicate.test(x) for x in self._data)
|
|
|
|
def allMatch(self, predicate):
|
|
return all(predicate.test(x) for x in self._data)
|
|
|
|
def noneMatch(self, predicate):
|
|
return not any(predicate.test(x) for x in self._data)
|
|
|
|
def findFirst(self):
|
|
if self._data:
|
|
return Optional.of(self._data[0])
|
|
return Optional.empty()
|
|
|
|
def findAny(self):
|
|
return self.findFirst()
|
|
|
|
def asDoubleStream(self):
|
|
return DoubleStream([float(x) for x in self._data])
|
|
|
|
def asLongStream(self):
|
|
return LongStream(self._data[:])
|
|
|
|
def boxed(self):
|
|
return Stream(self._data[:])
|
|
|
|
def iterator(self):
|
|
return iter(self._data)
|
|
|
|
def _get_data(self):
|
|
return self._data
|
|
|
|
@staticmethod
|
|
def of(*args):
|
|
return IntStream(list(args))
|
|
|
|
@staticmethod
|
|
def empty():
|
|
return IntStream([])
|
|
|
|
@staticmethod
|
|
def concat(a, b):
|
|
return IntStream(list(a._data) + list(b._data))
|
|
|
|
@staticmethod
|
|
def range(start, end):
|
|
return IntStream(list(range(start, end)))
|
|
|
|
@staticmethod
|
|
def rangeClosed(start, end):
|
|
return IntStream(list(range(start, end + 1)))
|
|
|
|
@staticmethod
|
|
def generate(supplier):
|
|
return IntStream([])
|
|
|
|
@staticmethod
|
|
def iterate(seed, has_next, next_fn):
|
|
return IntStream([])
|
|
|
|
class Builder:
|
|
def __init__(self):
|
|
self._impl = IntStreamBuilder()
|
|
|
|
def accept(self, t):
|
|
self._impl.accept(t)
|
|
|
|
def add(self, t):
|
|
self._impl.add(t)
|
|
return self
|
|
|
|
def build(self):
|
|
return self._impl.build()
|
|
|
|
|
|
# ============================================================
|
|
# LongStream
|
|
# ============================================================
|
|
|
|
class LongStream(BaseStream):
|
|
"""java.util.stream.LongStream"""
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = [int(x) for x in (data or [])]
|
|
|
|
def filter(self, predicate):
|
|
return LongStream([x for x in self._data if predicate.test(x)])
|
|
|
|
def map(self, mapper):
|
|
return LongStream([mapper.applyAsLong(x) for x in self._data])
|
|
|
|
def mapToObj(self, mapper):
|
|
return Stream([mapper.apply(x) for x in self._data])
|
|
|
|
def mapToInt(self, mapper):
|
|
return IntStream([mapper.applyAsInt(x) for x in self._data])
|
|
|
|
def mapToDouble(self, mapper):
|
|
return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
|
|
|
|
def flatMap(self, mapper):
|
|
results = []
|
|
for x in self._data:
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, LongStream):
|
|
results.extend(stream._data)
|
|
return LongStream(results)
|
|
|
|
def distinct(self):
|
|
return LongStream(list(set(self._data)))
|
|
|
|
def sorted(self):
|
|
return LongStream(sorted(self._data))
|
|
|
|
def peek(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
return LongStream(self._data[:])
|
|
|
|
def limit(self, max_size):
|
|
return LongStream(self._data[:max_size])
|
|
|
|
def skip(self, n):
|
|
return LongStream(self._data[n:])
|
|
|
|
def forEach(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
|
|
def forEachOrdered(self, action):
|
|
self.forEach(action)
|
|
|
|
def toArray(self):
|
|
return list(self._data)
|
|
|
|
def reduce(self, identity_or_op, op=None):
|
|
if op is None:
|
|
if not self._data:
|
|
return Optional.empty()
|
|
result = self._data[0]
|
|
for x in self._data[1:]:
|
|
result = identity_or_op.applyAsLong(result, x)
|
|
return Optional.of(result)
|
|
result = identity_or_op
|
|
for x in self._data:
|
|
result = op.applyAsLong(result, x)
|
|
return result
|
|
|
|
def sum(self):
|
|
return sum(self._data)
|
|
|
|
def min(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(min(self._data))
|
|
|
|
def max(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(max(self._data))
|
|
|
|
def count(self):
|
|
return len(self._data)
|
|
|
|
def average(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(sum(self._data) / len(self._data))
|
|
|
|
def summaryStatistics(self):
|
|
return LongSummaryStatistics(self._data)
|
|
|
|
def anyMatch(self, predicate):
|
|
return any(predicate.test(x) for x in self._data)
|
|
|
|
def allMatch(self, predicate):
|
|
return all(predicate.test(x) for x in self._data)
|
|
|
|
def noneMatch(self, predicate):
|
|
return not any(predicate.test(x) for x in self._data)
|
|
|
|
def findFirst(self):
|
|
if self._data:
|
|
return Optional.of(self._data[0])
|
|
return Optional.empty()
|
|
|
|
def findAny(self):
|
|
return self.findFirst()
|
|
|
|
def asDoubleStream(self):
|
|
return DoubleStream([float(x) for x in self._data])
|
|
|
|
def boxed(self):
|
|
return Stream(self._data[:])
|
|
|
|
def iterator(self):
|
|
return iter(self._data)
|
|
|
|
def _get_data(self):
|
|
return self._data
|
|
|
|
@staticmethod
|
|
def of(*args):
|
|
return LongStream(list(args))
|
|
|
|
@staticmethod
|
|
def empty():
|
|
return LongStream([])
|
|
|
|
@staticmethod
|
|
def concat(a, b):
|
|
return LongStream(list(a._data) + list(b._data))
|
|
|
|
@staticmethod
|
|
def range(start, end):
|
|
return LongStream(list(range(start, end)))
|
|
|
|
@staticmethod
|
|
def rangeClosed(start, end):
|
|
return LongStream(list(range(start, end + 1)))
|
|
|
|
class Builder:
|
|
def __init__(self):
|
|
self._impl = LongStreamBuilder()
|
|
|
|
def accept(self, t):
|
|
self._impl.accept(t)
|
|
|
|
def add(self, t):
|
|
self._impl.add(t)
|
|
return self
|
|
|
|
def build(self):
|
|
return self._impl.build()
|
|
|
|
|
|
# ============================================================
|
|
# DoubleStream
|
|
# ============================================================
|
|
|
|
class DoubleStream(BaseStream):
|
|
"""java.util.stream.DoubleStream"""
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = [float(x) for x in (data or [])]
|
|
|
|
def filter(self, predicate):
|
|
return DoubleStream([x for x in self._data if predicate.test(x)])
|
|
|
|
def map(self, mapper):
|
|
return DoubleStream([mapper.applyAsDouble(x) for x in self._data])
|
|
|
|
def mapToObj(self, mapper):
|
|
return Stream([mapper.apply(x) for x in self._data])
|
|
|
|
def mapToInt(self, mapper):
|
|
return IntStream([mapper.applyAsInt(x) for x in self._data])
|
|
|
|
def mapToLong(self, mapper):
|
|
return LongStream([mapper.applyAsLong(x) for x in self._data])
|
|
|
|
def flatMap(self, mapper):
|
|
results = []
|
|
for x in self._data:
|
|
stream = mapper.apply(x)
|
|
if isinstance(stream, DoubleStream):
|
|
results.extend(stream._data)
|
|
return DoubleStream(results)
|
|
|
|
def distinct(self):
|
|
return DoubleStream(list(set(self._data)))
|
|
|
|
def sorted(self):
|
|
return DoubleStream(sorted(self._data))
|
|
|
|
def peek(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
return DoubleStream(self._data[:])
|
|
|
|
def limit(self, max_size):
|
|
return DoubleStream(self._data[:max_size])
|
|
|
|
def skip(self, n):
|
|
return DoubleStream(self._data[n:])
|
|
|
|
def forEach(self, action):
|
|
for x in self._data:
|
|
action.accept(x)
|
|
|
|
def forEachOrdered(self, action):
|
|
self.forEach(action)
|
|
|
|
def toArray(self):
|
|
return list(self._data)
|
|
|
|
def reduce(self, identity_or_op, op=None):
|
|
if op is None:
|
|
if not self._data:
|
|
return Optional.empty()
|
|
result = self._data[0]
|
|
for x in self._data[1:]:
|
|
result = identity_or_op.applyAsDouble(result, x)
|
|
return Optional.of(result)
|
|
result = identity_or_op
|
|
for x in self._data:
|
|
result = op.applyAsDouble(result, x)
|
|
return result
|
|
|
|
def sum(self):
|
|
return sum(self._data)
|
|
|
|
def min(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(min(self._data))
|
|
|
|
def max(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(max(self._data))
|
|
|
|
def count(self):
|
|
return len(self._data)
|
|
|
|
def average(self):
|
|
if not self._data:
|
|
return Optional.empty()
|
|
return Optional.of(sum(self._data) / len(self._data))
|
|
|
|
def summaryStatistics(self):
|
|
return DoubleSummaryStatistics(self._data)
|
|
|
|
def anyMatch(self, predicate):
|
|
return any(predicate.test(x) for x in self._data)
|
|
|
|
def allMatch(self, predicate):
|
|
return all(predicate.test(x) for x in self._data)
|
|
|
|
def noneMatch(self, predicate):
|
|
return not any(predicate.test(x) for x in self._data)
|
|
|
|
def findFirst(self):
|
|
if self._data:
|
|
return Optional.of(self._data[0])
|
|
return Optional.empty()
|
|
|
|
def findAny(self):
|
|
return self.findFirst()
|
|
|
|
def iterator(self):
|
|
return iter(self._data)
|
|
|
|
def _get_data(self):
|
|
return self._data
|
|
|
|
@staticmethod
|
|
def of(*args):
|
|
return DoubleStream(list(args))
|
|
|
|
@staticmethod
|
|
def empty():
|
|
return DoubleStream([])
|
|
|
|
@staticmethod
|
|
def concat(a, b):
|
|
return DoubleStream(list(a._data) + list(b._data))
|
|
|
|
@staticmethod
|
|
def generate(supplier):
|
|
return DoubleStream([])
|
|
|
|
class Builder:
|
|
def __init__(self):
|
|
self._impl = DoubleStreamBuilder()
|
|
|
|
def accept(self, t):
|
|
self._impl.accept(t)
|
|
|
|
def add(self, t):
|
|
self._impl.add(t)
|
|
return self
|
|
|
|
def build(self):
|
|
return self._impl.build()
|
|
|
|
|
|
# ============================================================
|
|
# Collector
|
|
# ============================================================
|
|
|
|
class Collector(Stub):
|
|
"""java.util.stream.Collector"""
|
|
class Characteristics:
|
|
CONCURRENT = "CONCURRENT"
|
|
UNORDERED = "UNORDERED"
|
|
IDENTITY_FINISH = "IDENTITY_FINISH"
|
|
|
|
def __init__(self, supplier, accumulator, combiner, finisher=None,
|
|
characteristics=None):
|
|
super().__init__()
|
|
self._supplier = supplier
|
|
self._accumulator = accumulator
|
|
self._combiner = combiner
|
|
self._finisher = finisher
|
|
self._characteristics = characteristics or []
|
|
|
|
def supplier(self):
|
|
return self._supplier
|
|
|
|
def accumulator(self):
|
|
return self._accumulator
|
|
|
|
def combiner(self):
|
|
return self._combiner
|
|
|
|
def finisher(self):
|
|
return self._finisher
|
|
|
|
def characteristics(self):
|
|
return self._characteristics
|
|
|
|
|
|
# ============================================================
|
|
# Collectors
|
|
# ============================================================
|
|
|
|
class Collectors(Stub):
|
|
"""java.util.stream.Collectors"""
|
|
@staticmethod
|
|
def toList():
|
|
class ToListCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: []
|
|
a = lambda lst, item: lst.append(item) or lst
|
|
c = lambda l1, l2: l1 + l2
|
|
super().__init__(s, a, c)
|
|
return ToListCollector()
|
|
|
|
@staticmethod
|
|
def toSet():
|
|
class ToSetCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: set()
|
|
a = lambda st, item: st.add(item) or st
|
|
c = lambda s1, s2: s1 | s2
|
|
super().__init__(s, a, c)
|
|
return ToSetCollector()
|
|
|
|
@staticmethod
|
|
def joining(delimiter="", prefix="", suffix=""):
|
|
class JoiningCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: []
|
|
a = lambda lst, item: lst.append(str(item)) or lst
|
|
c = lambda l1, l2: l1 + l2
|
|
f = lambda lst: prefix + delimiter.join(lst) + suffix
|
|
super().__init__(s, a, c, f)
|
|
return JoiningCollector()
|
|
|
|
@staticmethod
|
|
def mapping(mapper, downstream):
|
|
class MappingCollector(Collector):
|
|
def __init__(self):
|
|
s = downstream.supplier()
|
|
a = lambda container, item: downstream.accumulator()(container, mapper(item))
|
|
c = downstream.combiner()
|
|
f = downstream.finisher()
|
|
super().__init__(s, a, c, f)
|
|
return MappingCollector()
|
|
|
|
@staticmethod
|
|
def filtering(predicate, downstream):
|
|
class FilteringCollector(Collector):
|
|
def __init__(self):
|
|
s = downstream.supplier()
|
|
a = lambda container, item: (
|
|
downstream.accumulator()(container, item)
|
|
if predicate(item) else container
|
|
)
|
|
c = downstream.combiner()
|
|
f = downstream.finisher()
|
|
super().__init__(s, a, c, f)
|
|
return FilteringCollector()
|
|
|
|
@staticmethod
|
|
def collectingAndThen(downstream, finisher):
|
|
class CollectingAndThenCollector(Collector):
|
|
def __init__(self):
|
|
s = downstream.supplier()
|
|
a = downstream.accumulator()
|
|
c = downstream.combiner()
|
|
f = lambda result: finisher(downstream.finisher()(result)) if downstream.finisher() else finisher(result)
|
|
super().__init__(s, a, c, f)
|
|
return CollectingAndThenCollector()
|
|
|
|
@staticmethod
|
|
def counting():
|
|
class CountingCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0]
|
|
a = lambda cnt, item: [cnt[0] + 1]
|
|
c = lambda c1, c2: [c1[0] + c2[0]]
|
|
f = lambda cnt: cnt[0]
|
|
super().__init__(s, a, c, f)
|
|
return CountingCollector()
|
|
|
|
@staticmethod
|
|
def summingInt(mapper):
|
|
class SummingIntCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0]
|
|
a = lambda total, item: [total[0] + mapper(item)]
|
|
c = lambda t1, t2: [t1[0] + t2[0]]
|
|
f = lambda total: total[0]
|
|
super().__init__(s, a, c, f)
|
|
return SummingIntCollector()
|
|
|
|
@staticmethod
|
|
def summingLong(mapper):
|
|
class SummingLongCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0]
|
|
a = lambda total, item: [total[0] + mapper(item)]
|
|
c = lambda t1, t2: [t1[0] + t2[0]]
|
|
f = lambda total: total[0]
|
|
super().__init__(s, a, c, f)
|
|
return SummingLongCollector()
|
|
|
|
@staticmethod
|
|
def summingDouble(mapper):
|
|
class SummingDoubleCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0.0]
|
|
a = lambda total, item: [total[0] + mapper(item)]
|
|
c = lambda t1, t2: [t1[0] + t2[0]]
|
|
f = lambda total: total[0]
|
|
super().__init__(s, a, c, f)
|
|
return SummingDoubleCollector()
|
|
|
|
@staticmethod
|
|
def averagingInt(mapper):
|
|
class AveragingIntCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0, 0] # [sum, count]
|
|
a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
|
|
c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
|
|
f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
|
|
super().__init__(s, a, c, f)
|
|
return AveragingIntCollector()
|
|
|
|
@staticmethod
|
|
def averagingLong(mapper):
|
|
class AveragingLongCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0, 0]
|
|
a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
|
|
c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
|
|
f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
|
|
super().__init__(s, a, c, f)
|
|
return AveragingLongCollector()
|
|
|
|
@staticmethod
|
|
def averagingDouble(mapper):
|
|
class AveragingDoubleCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: [0.0, 0]
|
|
a = lambda acc, item: [acc[0] + mapper(item), acc[1] + 1]
|
|
c = lambda a1, a2: [a1[0] + a2[0], a1[1] + a2[1]]
|
|
f = lambda acc: acc[0] / acc[1] if acc[1] > 0 else 0.0
|
|
super().__init__(s, a, c, f)
|
|
return AveragingDoubleCollector()
|
|
|
|
@staticmethod
|
|
def reducing(identity, mapper_or_op, op=None):
|
|
class ReducingCollector(Collector):
|
|
def __init__(self):
|
|
if op is None:
|
|
s = lambda: [identity]
|
|
a = lambda acc, item: [acc[0] + mapper_or_op(item)]
|
|
c = lambda a1, a2: [a1[0] + a2[0]]
|
|
f = lambda acc: acc[0]
|
|
else:
|
|
s = lambda: [identity]
|
|
a = lambda acc, item: [mapper_or_op.apply(acc[0], item)]
|
|
c = lambda a1, a2: [a1[0] + a2[0]]
|
|
f = lambda acc: acc[0]
|
|
super().__init__(s, a, c, f)
|
|
return ReducingCollector()
|
|
|
|
@staticmethod
|
|
def groupingBy(classifier, downstream_or_map_factory=None, downstream=None):
|
|
class GroupingByCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: {}
|
|
a = lambda m, item: (
|
|
m.setdefault(classifier(item), []).append(item) or m
|
|
)
|
|
c = lambda m1, m2: (
|
|
{k: m1.get(k, []) + m2.get(k, []) for k in set(m1) | set(m2)}
|
|
)
|
|
f = None
|
|
super().__init__(s, a, c, f)
|
|
return GroupingByCollector()
|
|
|
|
@staticmethod
|
|
def partitioningBy(predicate, downstream=None):
|
|
class PartitioningByCollector(Collector):
|
|
def __init__(self):
|
|
s = lambda: {True: [], False: []}
|
|
a = lambda m, item: (
|
|
m[True].append(item) if predicate(item) else m[False].append(item)
|
|
) or m
|
|
c = lambda m1, m2: {
|
|
True: m1[True] + m2[True],
|
|
False: m1[False] + m2[False]
|
|
}
|
|
super().__init__(s, a, c)
|
|
return PartitioningByCollector()
|
|
|
|
@staticmethod
|
|
def toMap(key_mapper, value_mapper, merge_function=None, map_supplier=None):
|
|
class ToMapCollector(Collector):
|
|
def __init__(self):
|
|
s = map_supplier or dict
|
|
a = lambda m, item: (
|
|
m.__setitem__(key_mapper(item), value_mapper(item)) or m
|
|
)
|
|
c = lambda m1, m2: {**m1, **m2}
|
|
super().__init__(s, a, c)
|
|
return ToMapCollector()
|
|
|
|
|
|
# ============================================================
|
|
# StreamSupport
|
|
# ============================================================
|
|
|
|
class StreamSupport(Stub):
|
|
"""java.util.stream.StreamSupport"""
|
|
@staticmethod
|
|
def stream(spliterator, parallel=False):
|
|
return Stream([])
|
|
|
|
@staticmethod
|
|
def intStream(spliterator, parallel=False):
|
|
return IntStream([])
|
|
|
|
@staticmethod
|
|
def longStream(spliterator, parallel=False):
|
|
return LongStream([])
|
|
|
|
@staticmethod
|
|
def doubleStream(spliterator, parallel=False):
|
|
return DoubleStream([])
|
|
|
|
|
|
# ============================================================
|
|
# Spliterator
|
|
# ============================================================
|
|
|
|
class Spliterator(Stub):
|
|
"""java.util.Spliterator"""
|
|
def __init__(self, data):
|
|
super().__init__()
|
|
self._data = list(data)
|
|
self._index = 0
|
|
|
|
def tryAdvance(self, action):
|
|
if self._index < len(self._data):
|
|
action.accept(self._data[self._index])
|
|
self._index += 1
|
|
return True
|
|
return False
|
|
|
|
def forEachRemaining(self, action):
|
|
while self._index < len(self._data):
|
|
action.accept(self._data[self._index])
|
|
self._index += 1
|
|
|
|
def estimateSize(self):
|
|
return len(self._data) - self._index
|
|
|
|
def getExactSizeIfKnown(self):
|
|
return self.estimateSize()
|
|
|
|
def characteristics(self):
|
|
return 0
|
|
|
|
ORDERED = 16
|
|
DISTINCT = 1
|
|
SORTED = 4
|
|
SIZED = 64
|
|
NONNULL = 256
|
|
IMMUTABLE = 1024
|
|
CONCURRENT = 4096
|
|
SUBSIZED = 16384
|
|
|
|
|
|
# ============================================================
|
|
# Summary Statistics
|
|
# ============================================================
|
|
|
|
class IntSummaryStatistics(Stub):
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = list(data) if data else []
|
|
|
|
def getCount(self):
|
|
return len(self._data)
|
|
|
|
def getSum(self):
|
|
return sum(self._data)
|
|
|
|
def getMin(self):
|
|
return min(self._data) if self._data else 0
|
|
|
|
def getMax(self):
|
|
return max(self._data) if self._data else 0
|
|
|
|
def getAverage(self):
|
|
return sum(self._data) / len(self._data) if self._data else 0.0
|
|
|
|
def accept(self, value):
|
|
self._data.append(int(value))
|
|
|
|
def combine(self, other):
|
|
self._data.extend(other._data)
|
|
|
|
|
|
class LongSummaryStatistics(Stub):
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = list(data) if data else []
|
|
|
|
def getCount(self):
|
|
return len(self._data)
|
|
|
|
def getSum(self):
|
|
return sum(self._data)
|
|
|
|
def getMin(self):
|
|
return min(self._data) if self._data else 0
|
|
|
|
def getMax(self):
|
|
return max(self._data) if self._data else 0
|
|
|
|
def getAverage(self):
|
|
return sum(self._data) / len(self._data) if self._data else 0.0
|
|
|
|
def accept(self, value):
|
|
self._data.append(int(value))
|
|
|
|
def combine(self, other):
|
|
self._data.extend(other._data)
|
|
|
|
|
|
class DoubleSummaryStatistics(Stub):
|
|
def __init__(self, data=None):
|
|
super().__init__()
|
|
self._data = list(data) if data else []
|
|
|
|
def getCount(self):
|
|
return len(self._data)
|
|
|
|
def getSum(self):
|
|
return sum(self._data)
|
|
|
|
def getMin(self):
|
|
return min(self._data) if self._data else 0.0
|
|
|
|
def getMax(self):
|
|
return max(self._data) if self._data else 0.0
|
|
|
|
def getAverage(self):
|
|
return sum(self._data) / len(self._data) if self._data else 0.0
|
|
|
|
def accept(self, value):
|
|
self._data.append(float(value))
|
|
|
|
def combine(self, other):
|
|
self._data.extend(other._data)
|
|
|
|
|
|
# ============================================================
|
|
# Pipeline / Operations stubs
|
|
# ============================================================
|
|
|
|
class AbstractPipeline(BaseStream):
|
|
"""java.util.stream.AbstractPipeline"""
|
|
pass
|
|
|
|
|
|
class ReferencePipeline(AbstractPipeline):
|
|
"""java.util.stream.ReferencePipeline"""
|
|
pass
|
|
|
|
|
|
class IntPipeline(AbstractPipeline):
|
|
"""java.util.stream.IntPipeline"""
|
|
pass
|
|
|
|
|
|
class LongPipeline(AbstractPipeline):
|
|
"""java.util.stream.LongPipeline"""
|
|
pass
|
|
|
|
|
|
class DoublePipeline(AbstractPipeline):
|
|
"""java.util.stream.DoublePipeline"""
|
|
pass
|
|
|
|
|
|
class Sink(Stub):
|
|
"""java.util.stream.Sink"""
|
|
def begin(self, size):
|
|
pass
|
|
|
|
def end(self):
|
|
pass
|
|
|
|
def cancellationRequested(self):
|
|
return False
|
|
|
|
def accept(self, t):
|
|
pass
|
|
|
|
|
|
class TerminalOp(Stub):
|
|
"""java.util.stream.TerminalOp"""
|
|
pass
|
|
|
|
|
|
class TerminalSink(Sink):
|
|
"""java.util.stream.TerminalSink"""
|
|
def get(self):
|
|
return None
|
|
|
|
|
|
class SliceOps(Stub):
|
|
"""java.util.stream.SliceOps"""
|
|
pass
|
|
|
|
|
|
class WhileOps(Stub):
|
|
"""java.util.stream.WhileOps"""
|
|
pass
|
|
|
|
|
|
class DistinctOps(Stub):
|
|
"""java.util.stream.DistinctOps"""
|
|
pass
|
|
|
|
|
|
class SortedOps(Stub):
|
|
"""java.util.stream.SortedOps"""
|
|
pass
|
|
|
|
|
|
class FindOps(Stub):
|
|
"""java.util.stream.FindOps"""
|
|
pass
|
|
|
|
|
|
class MatchOps(Stub):
|
|
"""java.util.stream.MatchOps"""
|
|
pass
|
|
|
|
|
|
class ReduceOps(Stub):
|
|
"""java.util.stream.ReduceOps"""
|
|
pass
|
|
|
|
|
|
class ForEachOps(Stub):
|
|
"""java.util.stream.ForEachOps"""
|
|
pass
|
|
|
|
|
|
class MapOps(Stub):
|
|
"""java.util.stream.MapOps"""
|
|
pass
|
|
|
|
|
|
class FilterOps(Stub):
|
|
"""java.util.stream.FilterOps"""
|
|
pass
|
|
|
|
|
|
class FlatMapOps(Stub):
|
|
"""java.util.stream.FlatMapOps"""
|
|
pass
|
|
|
|
|
|
class PeekOps(Stub):
|
|
"""java.util.stream.PeekOps"""
|
|
pass |