/** * Returns a {@code DoubleCollector} that produces the sum of the input * elements. If no elements are present, the result is 0.0. * * @return a {@code DoubleCollector} that produces the sum of the input * elements */ static DoubleCollector<?, Double> summing() { // Using DoubleSummaryStatistics as Kahan algorithm is implemented there return summarizing().andThen(DoubleSummaryStatistics::getSum); }
/** * Adapts this collector to perform an additional finishing transformation. * * @param <RR> result type of the resulting collector * @param finisher a function to be applied to the final result of this * collector * @return a collector which performs the action of this collector, followed * by an additional finishing step * @since 0.3.7 */ default <RR> DoubleCollector<A, RR> andThen(Function<R, RR> finisher) { return of(supplier(), doubleAccumulator(), merger(), finisher().andThen(finisher)); }
/** * Returns a {@code DoubleCollector} implementing a "group by" operation on * input numbers, grouping them according to a classification function, and * returning the results in a {@code Map}. * * <p> * The classification function maps elements to some key type {@code K}. The * collector produces a {@code Map<K, double[]>} whose keys are the values * resulting from applying the classification function to the input numbers, * and whose corresponding values are arrays containing the input numbers * which map to the associated key under the classification function. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Map} objects returned. * * @param <K> the type of the keys * @param classifier the classifier function mapping input elements to keys * @return a {@code DoubleCollector} implementing the group-by operation */ static <K> DoubleCollector<?, Map<K, double[]>> groupingBy(DoubleFunction<? extends K> classifier) { return groupingBy(classifier, toArray()); }
/** * Returns a {@code DoubleCollector} which partitions the input elements * according to a {@code DoublePredicate}, and organizes them into a * {@code Map<Boolean, double[]>}. * * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Map} returned. * * @param predicate a predicate used for classifying input elements * @return a {@code DoubleCollector} implementing the partitioning operation */ static DoubleCollector<?, Map<Boolean, double[]>> partitioningBy(DoublePredicate predicate) { return partitioningBy(predicate, toArray()); }
/** * Performs a mutable reduction operation on the elements of this stream * using an {@link DoubleCollector} which encapsulates the supplier, * accumulator and merger functions making easier to reuse collection * strategies. * * <p> * Like {@link #reduce(double, DoubleBinaryOperator)}, {@code collect} * operations can be parallelized without requiring additional * synchronization. * * <p> * This is a terminal operation. * * @param <A> the intermediate accumulation type of the * {@code DoubleCollector} * @param <R> type of the result * @param collector the {@code DoubleCollector} describing the reduction * @return the result of the reduction * @see #collect(Supplier, ObjDoubleConsumer, BiConsumer) * @since 0.3.0 */ @SuppressWarnings("unchecked") public <A, R> R collect(DoubleCollector<A, R> collector) { if (collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) return (R) collect(collector.supplier(), collector.doubleAccumulator(), collector.merger()); return collector.finisher().apply(collect(collector.supplier(), collector.doubleAccumulator(), collector .merger())); }
/** * Returns a {@code DoubleCollector} that produces the array of the input * elements. If no elements are present, the result is an empty array. * * @return a {@code DoubleCollector} that produces the array of the input * elements */ static DoubleCollector<?, double[]> toArray() { return of(DoubleBuffer::new, DoubleBuffer::add, DoubleBuffer::addAll, DoubleBuffer::toArray); }
Supplier<A> downstreamSupplier = downstream.supplier(); Function<K, A> supplier = k -> downstreamSupplier.get(); ObjDoubleConsumer<A> downstreamAccumulator = downstream.doubleAccumulator(); ObjDoubleConsumer<Map<K, A>> accumulator = (m, t) -> { K key = Objects.requireNonNull(classifier.apply(t));
/** * A function that folds a value into a mutable result container. * * The default implementation calls {@link #doubleAccumulator()} on unboxed * value. * * @return a function which folds a value into a mutable result container */ @Override default BiConsumer<A, Double> accumulator() { return doubleAccumulator()::accept; }
/** * Returns a {@link String} which is the concatenation of the results of * calling {@link String#valueOf(double)} on each element of this stream, * separated by the specified delimiter, in encounter order. * * <p> * This is a terminal operation. * * @param delimiter the delimiter to be used between each element * @return the result of concatenation. For empty input stream empty String * is returned. * @since 0.3.1 */ public String joining(CharSequence delimiter) { return collect(DoubleCollector.joining(delimiter)); }
/** * Adapts a {@code Collector} which accepts elements of type {@code Double} * to a {@code DoubleCollector}. * * @param <A> The intermediate accumulation type of the collector * @param <R> The final result type of the collector * @param collector a {@code Collector} to adapt * @return a {@code DoubleCollector} which behaves in the same way as input * collector. */ static <A, R> DoubleCollector<?, R> of(Collector<Double, A, R> collector) { if (collector instanceof DoubleCollector) { return (DoubleCollector<A, R>) collector; } return mappingToObj(Double::valueOf, collector); }
/** * Returns a {@code DoubleCollector} implementing a cascaded "group by" * operation on input numbers, grouping them according to a classification * function, and then performing a reduction operation on the values * associated with a given key using the specified downstream * {@code IntCollector}. * * <p> * The classification function maps elements to some key type {@code K}. The * downstream collector produces a result of type {@code D}. The resulting * collector produces a {@code Map<K, D>}. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Map} returned. * * @param <K> the type of the keys * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param classifier a classifier function mapping input elements to keys * @param downstream a {@code DoubleCollector} implementing the downstream * reduction * @return a {@code DoubleCollector} implementing the cascaded group-by * operation */ static <K, D, A> DoubleCollector<?, Map<K, D>> groupingBy(DoubleFunction<? extends K> classifier, DoubleCollector<A, D> downstream) { return groupingBy(classifier, HashMap::new, downstream); }
/** * Adapts a {@code DoubleCollector} to another one by applying a mapping * function to each input element before accumulation. * * @param <A> intermediate accumulation type of the downstream collector * @param <R> result type of collector * @param mapper a function to be applied to the input elements * @param downstream a collector which will accept mapped values * @return a collector which applies the mapping function to the input * elements and provides the mapped results to the downstream * collector */ static <A, R> DoubleCollector<?, R> mapping(DoubleUnaryOperator mapper, DoubleCollector<A, R> downstream) { ObjDoubleConsumer<A> downstreamAccumulator = downstream.doubleAccumulator(); return new DoubleCollectorImpl<>(downstream.supplier(), (r, t) -> downstreamAccumulator.accept(r, mapper .applyAsDouble(t)), downstream.merger(), downstream.finisher(), downstream.characteristics()); }
/** * Returns a {@code DoubleCollector} which returns summary statistics for * the input elements. * * @return a {@code DoubleCollector} implementing the summary-statistics * reduction */ static DoubleCollector<?, DoubleSummaryStatistics> summarizing() { return of(DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept, DoubleSummaryStatistics::combine); }
/** * Returns a {@code DoubleCollector} which partitions the input numbers * according to a {@code DoublePredicate}, reduces the values in each * partition according to another {@code IntCollector}, and organizes them * into a {@code Map<Boolean, D>} whose values are the result of the * downstream reduction. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Map} returned. * * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param predicate a predicate used for classifying input elements * @param downstream a {@code DoubleCollector} implementing the downstream * reduction * @return a {@code DoubleCollector} implementing the cascaded partitioning * operation */ static <A, D> DoubleCollector<?, Map<Boolean, D>> partitioningBy(DoublePredicate predicate, DoubleCollector<A, D> downstream) { ObjDoubleConsumer<A> downstreamAccumulator = downstream.doubleAccumulator(); ObjDoubleConsumer<BooleanMap<A>> accumulator = (result, t) -> downstreamAccumulator.accept( predicate.test(t) ? result.trueValue : result.falseValue, t); return BooleanMap.partialCollector(downstream).asDouble(accumulator); }
/** * Returns a {@link String} which is the concatenation of the results of * calling {@link String#valueOf(double)} on each element of this stream, * separated by the specified delimiter, with the specified prefix and * suffix in encounter order. * * <p> * This is a terminal operation. * * @param delimiter the delimiter to be used between each element * @param prefix the sequence of characters to be used at the beginning of * the joined result * @param suffix the sequence of characters to be used at the end of the * joined result * @return the result of concatenation. For empty input stream * {@code prefix + suffix} is returned. * @since 0.3.1 */ public String joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return collect(DoubleCollector.joining(delimiter, prefix, suffix)); }
/** * Returns a {@code DoubleCollector} that produces the arithmetic mean of * the input elements or an empty optional if no elements are collected. * * @return a {@code DoubleCollector} that produces the arithmetic mean of * the input elements * @since 0.3.7 */ static DoubleCollector<?, OptionalDouble> averaging() { return summarizing().andThen( dss -> dss.getCount() == 0L ? OptionalDouble.empty() : OptionalDouble.of(dss.getAverage())); }
/** * Returns a {@code DoubleCollector} that produces the {@code float[]} array * of the input elements converting them via {@code (float)} casting. If no * elements are present, the result is an empty array. * * @return a {@code DoubleCollector} that produces the {@code float[]} array * of the input elements */ static DoubleCollector<?, float[]> toFloatArray() { return of(FloatBuffer::new, FloatBuffer::add, FloatBuffer::addAll, FloatBuffer::toArray); }
/** * Returns a {@code DoubleCollector} which performs a reduction of its input * numbers under a specified {@code IntBinaryOperator} using the provided * identity. * * @param identity the identity value for the reduction (also, the value * that is returned when there are no input elements) * @param op a {@code DoubleBinaryOperator} used to reduce the input numbers * @return a {@code DoubleCollector} which implements the reduction * operation */ static DoubleCollector<?, Double> reducing(double identity, DoubleBinaryOperator op) { return of(() -> new double[] { identity }, (box, i) -> box[0] = op.applyAsDouble(box[0], i), (box1, box2) -> box1[0] = op.applyAsDouble(box1[0], box2[0]), UNBOX_DOUBLE); }
/** * Returns a {@code DoubleCollector} which performs a reduction of its input * numbers under a specified {@link DoubleBinaryOperator}. The result is * described as an {@link OptionalDouble}. * * @param op a {@code DoubleBinaryOperator} used to reduce the input numbers * @return a {@code DoubleCollector} which implements the reduction * operation. */ static DoubleCollector<?, OptionalDouble> reducing(DoubleBinaryOperator op) { return of(PrimitiveBox::new, (box, d) -> { if (!box.b) { box.b = true; box.d = d; } else { box.d = op.applyAsDouble(box.d, d); } }, (box1, box2) -> { if (box2.b) { if (!box1.b) { box1.from(box2); } else { box1.d = op.applyAsDouble(box1.d, box2.d); } } }, PrimitiveBox::asDouble); }