/* * Copyright 2015, 2016 Tagir Valeev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package one.util.streamex; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Deque; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Map.Entry; import java.util.Optional; import java.util.OptionalLong; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; import java.util.stream.Collector; import java.util.stream.Collector.Characteristics; import java.util.stream.Collectors; import java.util.stream.Stream; import static one.util.streamex.StreamExInternals.*; /** * Implementations of several collectors in addition to ones available in JDK. * * @author Tagir Valeev * @see Collectors * @see Joining * @since 0.3.2 */ public final class MoreCollectors { private MoreCollectors() { throw new UnsupportedOperationException(); } /** * Returns a {@code Collector} which just ignores the input and calls the * provided supplier once to return the output. * * @param <T> the type of input elements * @param <U> the type of output * @param supplier the supplier of the output * @return a {@code Collector} which just ignores the input and calls the * provided supplier once to return the output. */ private static <T, U> Collector<T, ?, U> empty(Supplier<U> supplier) { return new CancellableCollectorImpl<>(() -> NONE, (acc, t) -> { // empty }, selectFirst(), acc -> supplier.get(), acc -> true, EnumSet.of(Characteristics.UNORDERED, Characteristics.CONCURRENT)); } private static <T> Collector<T, ?, List<T>> empty() { return empty(ArrayList<T>::new); } /** * Returns a {@code Collector} that accumulates the input elements into a * new array. * * The operation performed by the returned collector is equivalent to * {@code stream.toArray(generator)}. This collector is mostly useful as a * downstream collector. * * @param <T> the type of the input elements * @param generator a function which produces a new array of the desired * type and the provided length * @return a {@code Collector} which collects all the input elements into an * array, in encounter order */ public static <T> Collector<T, ?, T[]> toArray(IntFunction<T[]> generator) { return Collectors.collectingAndThen(Collectors.toList(), list -> list.toArray(generator.apply(list.size()))); } /** * Returns a {@code Collector} which produces a boolean array containing the * results of applying the given predicate to the input elements, in * encounter order. * * @param <T> the type of the input elements * @param predicate a non-interfering, stateless predicate to apply to each * input element. The result values of this predicate are collected * to the resulting boolean array. * @return a {@code Collector} which collects the results of the predicate * function to the boolean array, in encounter order. * @since 0.3.8 */ public static <T> Collector<T, ?, boolean[]> toBooleanArray(Predicate<T> predicate) { return PartialCollector.booleanArray().asRef((box, t) -> { if (predicate.test(t)) box.a.set(box.b); box.b = StrictMath.addExact(box.b, 1); }); } /** * Returns a {@code Collector} that accumulates the input enum values into a * new {@code EnumSet}. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the resulting set * contains all possible enum values. * * @param <T> the type of the input elements * @param enumClass the class of input enum values * @return a {@code Collector} which collects all the input elements into a * {@code EnumSet} */ public static <T extends Enum<T>> Collector<T, ?, EnumSet<T>> toEnumSet(Class<T> enumClass) { int size = EnumSet.allOf(enumClass).size(); return new CancellableCollectorImpl<>(() -> EnumSet.noneOf(enumClass), EnumSet::add, (s1, s2) -> { s1.addAll(s2); return s1; }, Function.identity(), set -> set.size() == size, UNORDERED_ID_CHARACTERISTICS); } /** * Returns a {@code Collector} which counts a number of distinct values the * mapper function returns for the stream elements. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.map(mapper).distinct().count()}. This collector is mostly * useful as a downstream collector. * * @param <T> the type of the input elements * @param mapper a function which classifies input elements. * @return a collector which counts a number of distinct classes the mapper * function returns for the stream elements. */ public static <T> Collector<T, ?, Integer> distinctCount(Function<? super T, ?> mapper) { return Collectors.collectingAndThen(Collectors.mapping(mapper, Collectors.toSet()), Set::size); } /** * Returns a {@code Collector} which collects into the {@link List} the * input elements for which given mapper function returns distinct results. * * <p> * For ordered source the order of collected elements is preserved. If the * same result is returned by mapper function for several elements, only the * first element is included into the resulting list. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.distinct(mapper).toList()}, but may work faster. * * @param <T> the type of the input elements * @param mapper a function which classifies input elements. * @return a collector which collects distinct elements to the {@code List}. * @since 0.3.8 */ public static <T> Collector<T, ?, List<T>> distinctBy(Function<? super T, ?> mapper) { return Collector.<T, Map<Object, T>, List<T>> of(LinkedHashMap::new, (map, t) -> map.putIfAbsent(mapper.apply( t), t), (m1, m2) -> { for (Entry<Object, T> e : m2.entrySet()) { m1.putIfAbsent(e.getKey(), e.getValue()); } return m1; }, map -> new ArrayList<>(map.values())); } /** * Returns a {@code Collector} accepting elements of type {@code T} that * counts the number of input elements and returns result as {@code Integer} * . If no elements are present, the result is 0. * * @param <T> the type of the input elements * @return a {@code Collector} that counts the input elements * @since 0.3.3 * @see Collectors#counting() */ public static <T> Collector<T, ?, Integer> countingInt() { return PartialCollector.intSum().asRef((acc, t) -> acc[0]++); } /** * Returns a {@code Collector} which aggregates the results of two supplied * collectors using the supplied finisher function. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if both downstream collectors are short-circuiting. The * collection might stop when both downstream collectors report that the * collection is complete. * * @param <T> the type of the input elements * @param <A1> the intermediate accumulation type of the first collector * @param <A2> the intermediate accumulation type of the second collector * @param <R1> the result type of the first collector * @param <R2> the result type of the second collector * @param <R> the final result type * @param c1 the first collector * @param c2 the second collector * @param finisher the function which merges two results into the single * one. * @return a {@code Collector} which aggregates the results of two supplied * collectors. */ public static <T, A1, A2, R1, R2, R> Collector<T, ?, R> pairing(Collector<? super T, A1, R1> c1, Collector<? super T, A2, R2> c2, BiFunction<? super R1, ? super R2, ? extends R> finisher) { EnumSet<Characteristics> c = EnumSet.noneOf(Characteristics.class); c.addAll(c1.characteristics()); c.retainAll(c2.characteristics()); c.remove(Characteristics.IDENTITY_FINISH); Supplier<A1> c1Supplier = c1.supplier(); Supplier<A2> c2Supplier = c2.supplier(); BiConsumer<A1, ? super T> c1Accumulator = c1.accumulator(); BiConsumer<A2, ? super T> c2Accumulator = c2.accumulator(); BinaryOperator<A1> c1Combiner = c1.combiner(); BinaryOperator<A2> c2combiner = c2.combiner(); Supplier<PairBox<A1, A2>> supplier = () -> new PairBox<>(c1Supplier.get(), c2Supplier.get()); BiConsumer<PairBox<A1, A2>, T> accumulator = (acc, v) -> { c1Accumulator.accept(acc.a, v); c2Accumulator.accept(acc.b, v); }; BinaryOperator<PairBox<A1, A2>> combiner = (acc1, acc2) -> { acc1.a = c1Combiner.apply(acc1.a, acc2.a); acc1.b = c2combiner.apply(acc1.b, acc2.b); return acc1; }; Function<PairBox<A1, A2>, R> resFinisher = acc -> { R1 r1 = c1.finisher().apply(acc.a); R2 r2 = c2.finisher().apply(acc.b); return finisher.apply(r1, r2); }; Predicate<A1> c1Finished = finished(c1); Predicate<A2> c2Finished = finished(c2); if (c1Finished != null && c2Finished != null) { Predicate<PairBox<A1, A2>> finished = acc -> c1Finished.test(acc.a) && c2Finished.test(acc.b); return new CancellableCollectorImpl<>(supplier, accumulator, combiner, resFinisher, finished, c); } return Collector.of(supplier, accumulator, combiner, resFinisher, c.toArray(new Characteristics[0])); } /** * Returns a {@code Collector} which finds the minimal and maximal element * according to the supplied comparator, then applies finisher function to * them producing the final result. * * <p> * This collector produces stable result for ordered stream: if several * minimal or maximal elements appear, the collector always selects the * first encountered. * * <p> * If there are no input elements, the finisher method is not called and * empty {@code Optional} is returned. Otherwise the finisher result is * wrapped into {@code Optional}. * * @param <T> the type of the input elements * @param <R> the type of the result wrapped into {@code Optional} * @param comparator comparator which is used to find minimal and maximal * element * @param finisher a {@link BiFunction} which takes minimal and maximal * element and produces the final result. * @return a {@code Collector} which finds minimal and maximal elements. */ public static <T, R> Collector<T, ?, Optional<R>> minMax(Comparator<? super T> comparator, BiFunction<? super T, ? super T, ? extends R> finisher) { return pairing(Collectors.minBy(comparator), Collectors.maxBy(comparator), (min, max) -> min.isPresent() ? Optional.of(finisher.apply(min.get(), max.get())) : Optional.empty()); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the * specified {@link Comparator}. The found elements are reduced using the * specified downstream {@code Collector}. * * @param <T> the type of the input elements * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param comparator a {@code Comparator} to compare the elements * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the maximal elements. * @see #maxAll(Comparator) * @see #maxAll(Collector) * @see #maxAll() */ public static <T, A, D> Collector<T, ?, D> maxAll(Comparator<? super T> comparator, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BinaryOperator<A> downstreamCombiner = downstream.combiner(); Supplier<PairBox<A, T>> supplier = () -> new PairBox<>(downstreamSupplier.get(), none()); BiConsumer<PairBox<A, T>, T> accumulator = (acc, t) -> { if (acc.b == NONE) { downstreamAccumulator.accept(acc.a, t); acc.b = t; } else { int cmp = comparator.compare(t, acc.b); if (cmp > 0) { acc.a = downstreamSupplier.get(); acc.b = t; } if (cmp >= 0) downstreamAccumulator.accept(acc.a, t); } }; BinaryOperator<PairBox<A, T>> combiner = (acc1, acc2) -> { if (acc2.b == NONE) { return acc1; } if (acc1.b == NONE) { return acc2; } int cmp = comparator.compare(acc1.b, acc2.b); if (cmp > 0) { return acc1; } if (cmp < 0) { return acc2; } acc1.a = downstreamCombiner.apply(acc1.a, acc2.a); return acc1; }; Function<PairBox<A, T>, D> finisher = acc -> downstream.finisher().apply(acc.a); return Collector.of(supplier, accumulator, combiner, finisher); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the * specified {@link Comparator}. The found elements are collected to * {@link List}. * * @param <T> the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds all the maximal elements and * collects them to the {@code List}. * @see #maxAll(Comparator, Collector) * @see #maxAll() */ public static <T> Collector<T, ?, List<T>> maxAll(Comparator<? super T> comparator) { return maxAll(comparator, Collectors.toList()); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the natural * order. The found elements are reduced using the specified downstream * {@code Collector}. * * @param <T> the type of the input elements * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the maximal elements. * @see #maxAll(Comparator, Collector) * @see #maxAll(Comparator) * @see #maxAll() */ public static <T extends Comparable<? super T>, A, D> Collector<T, ?, D> maxAll(Collector<T, A, D> downstream) { return maxAll(Comparator.<T> naturalOrder(), downstream); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the natural * order. The found elements are collected to {@link List}. * * @param <T> the type of the input elements * @return a {@code Collector} which finds all the maximal elements and * collects them to the {@code List}. * @see #maxAll(Comparator) * @see #maxAll(Collector) */ public static <T extends Comparable<? super T>> Collector<T, ?, List<T>> maxAll() { return maxAll(Comparator.<T> naturalOrder(), Collectors.toList()); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the * specified {@link Comparator}. The found elements are reduced using the * specified downstream {@code Collector}. * * @param <T> the type of the input elements * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param comparator a {@code Comparator} to compare the elements * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the minimal elements. * @see #minAll(Comparator) * @see #minAll(Collector) * @see #minAll() */ public static <T, A, D> Collector<T, ?, D> minAll(Comparator<? super T> comparator, Collector<T, A, D> downstream) { return maxAll(comparator.reversed(), downstream); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the * specified {@link Comparator}. The found elements are collected to * {@link List}. * * @param <T> the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds all the minimal elements and * collects them to the {@code List}. * @see #minAll(Comparator, Collector) * @see #minAll() */ public static <T> Collector<T, ?, List<T>> minAll(Comparator<? super T> comparator) { return maxAll(comparator.reversed(), Collectors.toList()); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the natural * order. The found elements are reduced using the specified downstream * {@code Collector}. * * @param <T> the type of the input elements * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the minimal elements. * @see #minAll(Comparator, Collector) * @see #minAll(Comparator) * @see #minAll() */ public static <T extends Comparable<? super T>, A, D> Collector<T, ?, D> minAll(Collector<T, A, D> downstream) { return maxAll(Comparator.<T> reverseOrder(), downstream); } /** * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the natural * order. The found elements are collected to {@link List}. * * @param <T> the type of the input elements * @return a {@code Collector} which finds all the minimal elements and * collects them to the {@code List}. * @see #minAll(Comparator) * @see #minAll(Collector) */ public static <T extends Comparable<? super T>> Collector<T, ?, List<T>> minAll() { return maxAll(Comparator.<T> reverseOrder(), Collectors.toList()); } /** * Returns a {@code Collector} which collects the stream element if stream * contains exactly one element. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>. * * @param <T> the type of the input elements * @return a collector which returns an {@link Optional} describing the only * element of the stream. For empty stream or stream containing more * than one element an empty {@code Optional} is returned. * @since 0.4.0 */ public static <T> Collector<T, ?, Optional<T>> onlyOne() { return new CancellableCollectorImpl<T, Box<Optional<T>>, Optional<T>>(Box::new, (box, t) -> box.a = box.a == null ? Optional.of(t) : Optional.empty(), (box1, box2) -> box1.a == null ? box2 : box2.a == null ? box1 : new Box<>(Optional.empty()), box -> box.a == null ? Optional.empty() : box.a, box -> box.a != null && !box.a.isPresent(), UNORDERED_CHARACTERISTICS); } /** * Returns a {@code Collector} which collects only the first stream element * if any. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.findFirst()}. This collector is mostly useful as a * downstream collector. * * @param <T> the type of the input elements * @return a collector which returns an {@link Optional} which describes the * first element of the stream. For empty stream an empty * {@code Optional} is returned. */ public static <T> Collector<T, ?, Optional<T>> first() { return new CancellableCollectorImpl<>(() -> new Box<T>(none()), (box, t) -> { if (box.a == NONE) box.a = t; }, (box1, box2) -> box1.a == NONE ? box2 : box1, box -> box.a == NONE ? Optional.empty() : Optional.of(box.a), box -> box.a != NONE, NO_CHARACTERISTICS); } /** * Returns a {@code Collector} which collects only the last stream element * if any. * * @param <T> the type of the input elements * @return a collector which returns an {@link Optional} which describes the * last element of the stream. For empty stream an empty * {@code Optional} is returned. */ public static <T> Collector<T, ?, Optional<T>> last() { return Collectors.reducing((u, v) -> v); } /** * Returns a {@code Collector} which collects at most specified number of * the first stream elements into the {@link List}. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.limit(n).collect(Collectors.toList())}. This collector is * mostly useful as a downstream collector. * * @param <T> the type of the input elements * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the first n * stream elements or less if the stream was shorter. */ public static <T> Collector<T, ?, List<T>> head(int n) { if (n <= 0) return empty(); return new CancellableCollectorImpl<>(ArrayList::new, (acc, t) -> { if (acc.size() < n) acc.add(t); }, (acc1, acc2) -> { acc1.addAll(acc2.subList(0, Math.min(acc2.size(), n - acc1.size()))); return acc1; }, Function.identity(), acc -> acc.size() >= n, ID_CHARACTERISTICS); } /** * Returns a {@code Collector} which collects at most specified number of * the last stream elements into the {@link List}. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * When supplied {@code n} is less or equal to zero, this method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> which ignores the input and produces an empty list. * * @param <T> the type of the input elements * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the last n * stream elements or less if the stream was shorter. */ public static <T> Collector<T, ?, List<T>> tail(int n) { if (n <= 0) return empty(); return Collector.<T, Deque<T>, List<T>> of(ArrayDeque::new, (acc, t) -> { if (acc.size() == n) acc.pollFirst(); acc.addLast(t); }, (acc1, acc2) -> { while (acc2.size() < n && !acc1.isEmpty()) { acc2.addFirst(acc1.pollLast()); } return acc2; }, ArrayList<T>::new); } /** * Returns a {@code Collector} which collects at most specified number of * the greatest stream elements according to the specified * {@link Comparator} into the {@link List}. The resulting {@code List} is * sorted in comparator reverse order (greatest element is the first). The * order of equal elements is the same as in the input stream. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.sorted(comparator.reversed()).limit(n).collect(Collectors.toList())} * , but usually performed much faster if {@code n} is much less than the * stream size. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * When supplied {@code n} is less or equal to zero, this method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> which ignores the input and produces an empty list. * * @param <T> the type of the input elements * @param comparator the comparator to compare the elements by * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the greatest * n stream elements or less if the stream was shorter. */ public static <T> Collector<T, ?, List<T>> greatest(Comparator<? super T> comparator, int n) { return least(comparator.reversed(), n); } /** * Returns a {@code Collector} which collects at most specified number of * the greatest stream elements according to the natural order into the * {@link List}. The resulting {@code List} is sorted in reverse order * (greatest element is the first). The order of equal elements is the same * as in the input stream. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.sorted(Comparator.reverseOrder()).limit(n).collect(Collectors.toList())} * , but usually performed much faster if {@code n} is much less than the * stream size. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * When supplied {@code n} is less or equal to zero, this method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> which ignores the input and produces an empty list. * * @param <T> the type of the input elements * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the greatest * n stream elements or less if the stream was shorter. */ public static <T extends Comparable<? super T>> Collector<T, ?, List<T>> greatest(int n) { return least(Comparator.<T> reverseOrder(), n); } /** * Returns a {@code Collector} which collects at most specified number of * the least stream elements according to the specified {@link Comparator} * into the {@link List}. The resulting {@code List} is sorted in comparator * order (least element is the first). The order of equal elements is the * same as in the input stream. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.sorted(comparator).limit(n).collect(Collectors.toList())}, * but usually performed much faster if {@code n} is much less than the * stream size. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * When supplied {@code n} is less or equal to zero, this method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> which ignores the input and produces an empty list. * * @param <T> the type of the input elements * @param comparator the comparator to compare the elements by * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the least n * stream elements or less if the stream was shorter. */ public static <T> Collector<T, ?, List<T>> least(Comparator<? super T> comparator, int n) { if (n <= 0) return empty(); if (n == 1) { return Collector.of(() -> new Box<T>(none()), (box, t) -> { if (box.a == NONE || comparator.compare(t, box.a) < 0) box.a = t; }, (box1, box2) -> (box2.a != NONE && (box1.a == NONE || comparator.compare(box2.a, box1.a) < 0)) ? box2 : box1, box -> box.a == NONE ? new ArrayList<>() : new ArrayList<>(Collections.singleton(box.a))); } if (n >= Integer.MAX_VALUE / 2) return collectingAndThen(Collectors.toList(), list -> { list.sort(comparator); if (list.size() <= n) return list; return new ArrayList<>(list.subList(0, n)); }); return Collector.<T, Limiter<T>, List<T>> of(() -> new Limiter<>(n, comparator), Limiter::put, Limiter::putAll, pq -> { pq.sort(); return new ArrayList<>(pq); }); } /** * Returns a {@code Collector} which collects at most specified number of * the least stream elements according to the natural order into the * {@link List}. The resulting {@code List} is sorted in natural order * (least element is the first). The order of equal elements is the same as * in the input stream. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.sorted().limit(n).collect(Collectors.toList())}, but * usually performed much faster if {@code n} is much less than the stream * size. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * <p> * When supplied {@code n} is less or equal to zero, this method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> which ignores the input and produces an empty list. * * @param <T> the type of the input elements * @param n maximum number of stream elements to preserve * @return a collector which returns a {@code List} containing the least n * stream elements or less if the stream was shorter. */ public static <T extends Comparable<? super T>> Collector<T, ?, List<T>> least(int n) { return least(Comparator.<T> naturalOrder(), n); } /** * Returns a {@code Collector} which finds the index of the minimal stream * element according to the specified {@link Comparator}. If there are * several minimal elements, the index of the first one is returned. * * @param <T> the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds the index of the minimal element. * @see #minIndex() * @since 0.3.5 */ public static <T> Collector<T, ?, OptionalLong> minIndex(Comparator<? super T> comparator) { class Container { T value; long count = 0; long index = -1; } return Collector.of(Container::new, (c, t) -> { if (c.index == -1 || comparator.compare(c.value, t) > 0) { c.value = t; c.index = c.count; } c.count++; }, (c1, c2) -> { if (c1.index == -1 || (c2.index != -1 && comparator.compare(c1.value, c2.value) > 0)) { c2.index += c1.count; c2.count += c1.count; return c2; } c1.count += c2.count; return c1; }, c -> c.index == -1 ? OptionalLong.empty() : OptionalLong.of(c.index)); } /** * Returns a {@code Collector} which finds the index of the minimal stream * element according to the elements natural order. If there are several * minimal elements, the index of the first one is returned. * * @param <T> the type of the input elements * @return a {@code Collector} which finds the index of the minimal element. * @see #minIndex(Comparator) * @since 0.3.5 */ public static <T extends Comparable<? super T>> Collector<T, ?, OptionalLong> minIndex() { return minIndex(Comparator.naturalOrder()); } /** * Returns a {@code Collector} which finds the index of the maximal stream * element according to the specified {@link Comparator}. If there are * several maximal elements, the index of the first one is returned. * * @param <T> the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds the index of the maximal element. * @see #maxIndex() * @since 0.3.5 */ public static <T> Collector<T, ?, OptionalLong> maxIndex(Comparator<? super T> comparator) { return minIndex(comparator.reversed()); } /** * Returns a {@code Collector} which finds the index of the maximal stream * element according to the elements natural order. If there are several * maximal elements, the index of the first one is returned. * * @param <T> the type of the input elements * @return a {@code Collector} which finds the index of the maximal element. * @see #maxIndex(Comparator) * @since 0.3.5 */ public static <T extends Comparable<? super T>> Collector<T, ?, OptionalLong> maxIndex() { return minIndex(Comparator.reverseOrder()); } /** * Returns a {@code Collector} implementing a cascaded "group by" operation * on input elements of type {@code T}, for classification function which * maps input elements to the enum values. The downstream reduction for * repeating keys is performed using the specified downstream * {@code Collector}. * * <p> * Unlike the {@link Collectors#groupingBy(Function, Collector)} collector * this collector produces an {@link EnumMap} which contains all possible * keys including keys which were never returned by the classification * function. These keys are mapped to the default collector value which is * equivalent to collecting an empty stream with the same collector. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. The * collection might stop when for every possible enum key the downstream * collection is known to be finished. * * @param <T> the type of the input elements * @param <K> the type of the enum values returned by the classifier * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param enumClass the class of enum values returned by the classifier * @param classifier a classifier function mapping input elements to enum * values * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} implementing the cascaded group-by operation * @see Collectors#groupingBy(Function, Collector) * @see #groupingBy(Function, Set, Supplier, Collector) * @since 0.3.7 */ public static <T, K extends Enum<K>, A, D> Collector<T, ?, EnumMap<K, D>> groupingByEnum(Class<K> enumClass, Function<? super T, K> classifier, Collector<? super T, A, D> downstream) { return groupingBy(classifier, EnumSet.allOf(enumClass), () -> new EnumMap<>(enumClass), downstream); } /** * Returns a {@code Collector} implementing a cascaded "group by" operation * on input elements of type {@code T}, grouping elements according to a * classification function, and then performing a reduction operation on the * values associated with a given key using the specified downstream * {@code Collector}. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Map} returned. * * <p> * The main difference of this collector from * {@link Collectors#groupingBy(Function, Collector)} is that it accepts * additional domain parameter which is the {@code Set} of all possible map * keys. If the mapper function produces the key out of domain, an * {@code IllegalStateException} will occur. If the mapper function does not * produce some of domain keys at all, they are also added to the result. * These keys are mapped to the default collector value which is equivalent * to collecting an empty stream with the same collector. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. The * collection might stop when for every possible key from the domain the * downstream collection is known to be finished. * * @param <T> the type of the input elements * @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 domain a domain of all possible key values * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} implementing the cascaded group-by operation * with given domain * * @see #groupingBy(Function, Set, Supplier, Collector) * @see #groupingByEnum(Class, Function, Collector) * @since 0.4.0 */ public static <T, K, D, A> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Set<K> domain, Collector<? super T, A, D> downstream) { return groupingBy(classifier, domain, HashMap::new, downstream); } /** * Returns a {@code Collector} implementing a cascaded "group by" operation * on input elements of type {@code T}, grouping elements according to a * classification function, and then performing a reduction operation on the * values associated with a given key using the specified downstream * {@code Collector}. The {@code Map} produced by the Collector is created * with the supplied factory function. * * <p> * The main difference of this collector from * {@link Collectors#groupingBy(Function, Supplier, Collector)} is that it * accepts additional domain parameter which is the {@code Set} of all * possible map keys. If the mapper function produces the key out of domain, * an {@code IllegalStateException} will occur. If the mapper function does * not produce some of domain keys at all, they are also added to the * result. These keys are mapped to the default collector value which is * equivalent to collecting an empty stream with the same collector. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. The * collection might stop when for every possible key from the domain the * downstream collection is known to be finished. * * @param <T> the type of the input elements * @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 <M> the type of the resulting {@code Map} * @param classifier a classifier function mapping input elements to keys * @param domain a domain of all possible key values * @param downstream a {@code Collector} implementing the downstream * reduction * @param mapFactory a function which, when called, produces a new empty * {@code Map} of the desired type * @return a {@code Collector} implementing the cascaded group-by operation * with given domain * * @see #groupingBy(Function, Set, Collector) * @see #groupingByEnum(Class, Function, Collector) * @since 0.4.0 */ public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy( Function<? super T, ? extends K> classifier, Set<K> domain, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); Collector<T, ?, M> groupingBy; Function<K, A> supplier = k -> { if (!domain.contains(k)) throw new IllegalStateException("Classifier returned value '" + k + "' which is out of domain"); return downstreamSupplier.get(); }; BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BiConsumer<Map<K, A>, T> accumulator = (m, t) -> { K key = Objects.requireNonNull(classifier.apply(t)); A container = m.computeIfAbsent(key, supplier); downstreamAccumulator.accept(container, t); }; PartialCollector<Map<K, A>, M> partial = PartialCollector.grouping(mapFactory, downstream); Predicate<A> downstreamFinished = finished(downstream); if (downstreamFinished != null) { int size = domain.size(); groupingBy = partial.asCancellable(accumulator, map -> { if (map.size() < size) return false; for (A container : map.values()) { if (!downstreamFinished.test(container)) return false; } return true; }); } else { groupingBy = partial.asRef(accumulator); } return collectingAndThen(groupingBy, map -> { Function<A, D> finisher = downstream.finisher(); domain.forEach(key -> map.computeIfAbsent(key, k -> finisher.apply(downstreamSupplier.get()))); return map; }); } /** * Returns a {@code Collector} which collects the intersection of the input * collections into the newly-created {@link Set}. * * <p> * The returned collector produces an empty set if the input is empty or * intersection of the input collections is empty. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code Set} returned. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the resulting * intersection is empty. * * @param <T> the type of the elements in the input collections * @param <S> the type of the input collections * @return a {@code Collector} which finds all the minimal elements and * collects them to the {@code List}. * @since 0.4.0 */ public static <T, S extends Collection<T>> Collector<S, ?, Set<T>> intersecting() { return new CancellableCollectorImpl<S, Box<Set<T>>, Set<T>>(Box::new, (b, t) -> { if (b.a == null) { b.a = new HashSet<>(t); } else { b.a.retainAll(t); } }, (b1, b2) -> { if (b1.a == null) return b2; if (b2.a != null) b1.a.retainAll(b2.a); return b1; }, b -> b.a == null ? Collections.emptySet() : b.a, b -> b.a != null && b.a.isEmpty(), UNORDERED_CHARACTERISTICS); } /** * Adapts a {@code Collector} to perform an additional finishing * transformation. * * <p> * Unlike {@link Collectors#collectingAndThen(Collector, Function)} this * method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. * * @param <T> the type of the input elements * @param <A> intermediate accumulation type of the downstream collector * @param <R> result type of the downstream collector * @param <RR> result type of the resulting collector * @param downstream a collector * @param finisher a function to be applied to the final result of the * downstream collector * @return a collector which performs the action of the downstream * collector, followed by an additional finishing step * @see Collectors#collectingAndThen(Collector, Function) * @since 0.4.0 */ public static <T, A, R, RR> Collector<T, A, RR> collectingAndThen(Collector<T, A, R> downstream, Function<R, RR> finisher) { Predicate<A> finished = finished(downstream); if (finished != null) { return new CancellableCollectorImpl<>(downstream.supplier(), downstream.accumulator(), downstream .combiner(), downstream.finisher().andThen(finisher), finished, downstream.characteristics() .contains(Characteristics.UNORDERED) ? UNORDERED_CHARACTERISTICS : NO_CHARACTERISTICS); } return Collectors.collectingAndThen(downstream, finisher); } /** * Returns a {@code Collector} which partitions the input elements according * to a {@code Predicate}, reduces the values in each partition according to * another {@code Collector}, and organizes them into a * {@code Map<Boolean, D>} whose values are the result of the downstream * reduction. * * <p> * Unlike {@link Collectors#partitioningBy(Predicate, Collector)} this * method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. * * @param <T> the type of the input elements * @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 Collector} implementing the downstream * reduction * @return a {@code Collector} implementing the cascaded partitioning * operation * @since 0.4.0 * @see Collectors#partitioningBy(Predicate, Collector) */ public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) { Predicate<A> finished = finished(downstream); if (finished != null) { BiConsumer<A, ? super T> accumulator = downstream.accumulator(); return BooleanMap.partialCollector(downstream).asCancellable((map, t) -> accumulator.accept(predicate.test( t) ? map.trueValue : map.falseValue, t), map -> finished.test(map.trueValue) && finished.test( map.falseValue)); } return Collectors.partitioningBy(predicate, downstream); } /** * Adapts a {@code Collector} accepting elements of type {@code U} to one * accepting elements of type {@code T} by applying a mapping function to * each input element before accumulation. * * <p> * Unlike {@link Collectors#mapping(Function, Collector)} this method * returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if the downstream collector is short-circuiting. * * @param <T> the type of the input elements * @param <U> type of elements accepted by downstream collector * @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 * @see Collectors#mapping(Function, Collector) * @since 0.4.0 */ public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) { Predicate<A> finished = finished(downstream); if (finished != null) { BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); return new CancellableCollectorImpl<>(downstream.supplier(), (acc, t) -> { if (!finished.test(acc)) downstreamAccumulator.accept(acc, mapper.apply(t)); }, downstream.combiner(), downstream.finisher(), finished, downstream.characteristics()); } return Collectors.mapping(mapper, downstream); } /** * Returns a collector which collects input elements to the new {@code List} * transforming them with the supplied function beforehand. * * <p> * This method behaves like * {@code Collectors.mapping(mapper, Collectors.toList())}. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * @param <T> the type of the input elements * @param <U> the resulting type of the mapper function * @param mapper a function to be applied to the input elements * @return a collector which applies the mapping function to the input * elements and collects the mapped results to the {@code List} * @see #mapping(Function, Collector) * @since 0.6.0 */ public static <T, U> Collector<T, ?, List<U>> mapping(Function<? super T, ? extends U> mapper) { return Collectors.mapping(mapper, Collectors.toList()); } /** * Adapts a {@code Collector} accepting elements of type {@code U} to one * accepting elements of type {@code T} by applying a flat mapping function * to each input element before accumulation. The flat mapping function maps * an input element to a {@link Stream stream} covering zero or more output * elements that are then accumulated downstream. Each mapped stream is * {@link java.util.stream.BaseStream#close() closed} after its contents * have been placed downstream. (If a mapped stream is {@code null} an empty * stream is used, instead.) * * <p> * This method is similar to {@code Collectors.flatMapping} method which * appears in JDK 9. However when downstream collector is * <a href="package-summary.html#ShortCircuitReduction">short-circuiting</a> * , this method will also return a short-circuiting collector. * * @param <T> the type of the input elements * @param <U> type of elements accepted by downstream collector * @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, which * returns a stream of results * @param downstream a collector which will receive the elements of the * stream returned by mapper * @return a collector which applies the mapping function to the input * elements and provides the flat mapped results to the downstream * collector * @since 0.4.1 */ public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) { BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); Predicate<A> finished = finished(downstream); if (finished != null) { return new CancellableCollectorImpl<>(downstream.supplier(), (acc, t) -> { if (finished.test(acc)) return; try (Stream<? extends U> stream = mapper.apply(t)) { if (stream != null) { stream.spliterator().forEachRemaining(u -> { downstreamAccumulator.accept(acc, u); if (finished.test(acc)) throw new CancelException(); }); } } catch (CancelException ex) { // ignore } }, downstream.combiner(), downstream.finisher(), finished, downstream.characteristics()); } return Collector.of(downstream.supplier(), (acc, t) -> { try (Stream<? extends U> stream = mapper.apply(t)) { if (stream != null) { stream.spliterator().forEachRemaining(u -> downstreamAccumulator.accept(acc, u)); } } }, downstream.combiner(), downstream.finisher(), downstream.characteristics().toArray(new Characteristics[0])); } /** * Returns a collector which launches a flat mapping function for each input * element and collects the elements of the resulting streams to the flat * {@code List}. Each mapped stream is * {@link java.util.stream.BaseStream#close() closed} after its contents * have been placed downstream. (If a mapped stream is {@code null} an empty * stream is used, instead.) * * <p> * This method behaves like {@code flatMapping(mapper, Collectors.toList())} * . * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * @param <T> the type of the input elements * @param <U> type of the resulting elements * @param mapper a function to be applied to the input elements, which * returns a stream of results * @return a collector which applies the mapping function to the input * elements and collects the flat mapped results to the {@code List} * @since 0.6.0 */ public static <T, U> Collector<T, ?, List<U>> flatMapping( Function<? super T, ? extends Stream<? extends U>> mapper) { return flatMapping(mapper, Collectors.toList()); } /** * Returns a {@code Collector} which passes only those elements to the * specified downstream collector which match given predicate. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a> if downstream collector is short-circuiting. * * <p> * The operation performed by the returned collector is equivalent to * {@code stream.filter(predicate).collect(downstream)}. This collector is * mostly useful as a downstream collector in cascaded operation involving * {@link #pairing(Collector, Collector, BiFunction)} collector. * * <p> * This method is similar to {@code Collectors.filtering} method which * appears in JDK 9. However when downstream collector is * <a href="package-summary.html#ShortCircuitReduction">short-circuiting</a> * , this method will also return a short-circuiting collector. * * @param <T> the type of the input elements * @param <A> intermediate accumulation type of the downstream collector * @param <R> result type of collector * @param predicate a filter function to be applied to the input elements * @param downstream a collector which will accept filtered values * @return a collector which applies the predicate to the input elements and * provides the elements for which predicate returned true to the * downstream collector * @see #pairing(Collector, Collector, BiFunction) * @since 0.4.0 */ public static <T, A, R> Collector<T, ?, R> filtering(Predicate<? super T> predicate, Collector<T, A, R> downstream) { BiConsumer<A, T> downstreamAccumulator = downstream.accumulator(); BiConsumer<A, T> accumulator = (acc, t) -> { if (predicate.test(t)) downstreamAccumulator.accept(acc, t); }; Predicate<A> finished = finished(downstream); if (finished != null) { return new CancellableCollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream .finisher(), finished, downstream.characteristics()); } return Collector.of(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream .characteristics().toArray(new Characteristics[0])); } /** * Returns a {@code Collector} which filters input elements by the supplied * predicate, collecting them to the list. * * <p> * This method behaves like * {@code filtering(predicate, Collectors.toList())}. * * <p> * There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * @param <T> the type of the input elements * @param predicate a filter function to be applied to the input elements * @return a collector which applies the predicate to the input elements and * collects the elements for which predicate returned true to the * {@code List} * @see #filtering(Predicate, Collector) * @since 0.6.0 */ public static <T> Collector<T, ?, List<T>> filtering(Predicate<? super T> predicate) { return filtering(predicate, Collectors.toList()); } /** * Returns a {@code Collector} which performs the bitwise-and operation of a * integer-valued function applied to the input elements. If no elements are * present, the result is empty {@link OptionalInt}. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the result is zero. * * @param <T> the type of the input elements * @param mapper a function extracting the property to be processed * @return a {@code Collector} that produces the bitwise-and operation of a * derived property * @since 0.4.0 */ public static <T> Collector<T, ?, OptionalInt> andingInt(ToIntFunction<T> mapper) { return new CancellableCollectorImpl<>(PrimitiveBox::new, (acc, t) -> { if (!acc.b) { acc.i = mapper.applyAsInt(t); acc.b = true; } else { acc.i &= mapper.applyAsInt(t); } }, (acc1, acc2) -> { if (!acc1.b) return acc2; if (!acc2.b) return acc1; acc1.i &= acc2.i; return acc1; }, PrimitiveBox::asInt, acc -> acc.b && acc.i == 0, UNORDERED_CHARACTERISTICS); } /** * Returns a {@code Collector} which performs the bitwise-and operation of a * long-valued function applied to the input elements. If no elements are * present, the result is empty {@link OptionalLong}. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the result is zero. * * @param <T> the type of the input elements * @param mapper a function extracting the property to be processed * @return a {@code Collector} that produces the bitwise-and operation of a * derived property * @since 0.4.0 */ public static <T> Collector<T, ?, OptionalLong> andingLong(ToLongFunction<T> mapper) { return new CancellableCollectorImpl<>(PrimitiveBox::new, (acc, t) -> { if (!acc.b) { acc.l = mapper.applyAsLong(t); acc.b = true; } else { acc.l &= mapper.applyAsLong(t); } }, (acc1, acc2) -> { if (!acc1.b) return acc2; if (!acc2.b) return acc1; acc1.l &= acc2.l; return acc1; }, PrimitiveBox::asLong, acc -> acc.b && acc.l == 0, UNORDERED_CHARACTERISTICS); } /** * Returns a {@code Collector} which computes a common prefix of input * {@code CharSequence} objects returning the result as {@code String}. For * empty input the empty {@code String} is returned. * * <p> * The returned {@code Collector} handles specially Unicode surrogate pairs: * the returned prefix may end with * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit"> * Unicode high-surrogate code unit</a> only if it's not succeeded by * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit"> * Unicode low-surrogate code unit</a> in any of the input sequences. * Normally the ending high-surrogate code unit is removed from the prefix. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the common prefix * is empty. * * @return a {@code Collector} which computes a common prefix. * @since 0.5.0 */ public static Collector<CharSequence, ?, String> commonPrefix() { BiConsumer<ObjIntBox<CharSequence>, CharSequence> accumulator = (acc, t) -> { if (acc.b == -1) { acc.a = t; acc.b = t.length(); } else if (acc.b > 0) { if (t.length() < acc.b) acc.b = t.length(); for (int i = 0; i < acc.b; i++) { if (acc.a.charAt(i) != t.charAt(i)) { if (i > 0 && Character.isHighSurrogate(t.charAt(i - 1)) && (Character.isLowSurrogate(t.charAt( i)) || Character.isLowSurrogate(acc.a.charAt(i)))) i--; acc.b = i; break; } } } }; return new CancellableCollectorImpl<>(() -> new ObjIntBox<>(null, -1), accumulator, (acc1, acc2) -> { if (acc1.b == -1) return acc2; if (acc2.b != -1) accumulator.accept(acc1, acc2.a.subSequence(0, acc2.b)); return acc1; }, acc -> acc.a == null ? "" : acc.a.subSequence(0, acc.b).toString(), acc -> acc.b == 0, UNORDERED_CHARACTERISTICS); } /** * Returns a {@code Collector} which computes a common suffix of input * {@code CharSequence} objects returning the result as {@code String}. For * empty input the empty {@code String} is returned. * * <p> * The returned {@code Collector} handles specially Unicode surrogate pairs: * the returned suffix may start with * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit"> * Unicode low-surrogate code unit</a> only if it's not preceded by * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit"> * Unicode high-surrogate code unit</a> in any of the input sequences. * Normally the starting low-surrogate code unit is removed from the suffix. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if the common suffix * is empty. * * @return a {@code Collector} which computes a common suffix. * @since 0.5.0 */ public static Collector<CharSequence, ?, String> commonSuffix() { BiConsumer<ObjIntBox<CharSequence>, CharSequence> accumulator = (acc, t) -> { if (acc.b == -1) { acc.a = t; acc.b = t.length(); } else if (acc.b > 0) { int aLen = acc.a.length(); int bLen = t.length(); if (bLen < acc.b) acc.b = bLen; for (int i = 0; i < acc.b; i++) { if (acc.a.charAt(aLen - 1 - i) != t.charAt(bLen - 1 - i)) { if (i > 0 && Character.isLowSurrogate(t.charAt(bLen - i)) && (Character.isHighSurrogate(t .charAt(bLen - 1 - i)) || Character.isHighSurrogate(acc.a.charAt(aLen - 1 - i)))) i--; acc.b = i; break; } } } }; return new CancellableCollectorImpl<>(() -> new ObjIntBox<>(null, -1), accumulator, (acc1, acc2) -> { if (acc1.b == -1) return acc2; if (acc2.b != -1) accumulator.accept(acc1, acc2.a.subSequence(acc2.a.length() - acc2.b, acc2.a.length())); return acc1; }, acc -> acc.a == null ? "" : acc.a.subSequence(acc.a.length() - acc.b, acc.a.length()).toString(), acc -> acc.b == 0, UNORDERED_CHARACTERISTICS); } /** * Returns a collector which collects input elements into {@code List} * removing the elements following their dominator element. The dominator * elements are defined according to given isDominator {@code BiPredicate}. * The isDominator relation must be transitive (if A dominates over B and B * dominates over C, then A also dominates over C). * * <p> * This operation is similar to * {@code streamEx.collapse(isDominator).toList()}. The important difference * is that in this method {@code BiPredicate} accepts not the adjacent * stream elements, but the leftmost element of the series (current * dominator) and the current element. * * <p> * For example, consider the stream of numbers: * * <pre>{@code * StreamEx<Integer> stream = StreamEx.of(1, 5, 3, 4, 2, 7); * }</pre> * * <p> * Using {@code stream.collapse((a, b) -> a >= b).toList()} you will get the * numbers which are bigger than their immediate predecessor ( * {@code [1, 5, 4, 7]}), because (3, 4) pair is not collapsed. However * using {@code stream.collect(dominators((a, b) -> a >= b))} you will get * the numbers which are bigger than any predecessor ({@code [1, 5, 7]}) as * 5 is the dominator element for the subsequent 3, 4 and 2. * * @param <T> type of the input elements. * @param isDominator a non-interfering, stateless, transitive * {@code BiPredicate} which returns true if the first argument is * the dominator for the second argument. * @return a collector which collects input element into {@code List} * leaving only dominator elements. * @see StreamEx#collapse(BiPredicate) * @since 0.5.1 */ public static <T> Collector<T, ?, List<T>> dominators(BiPredicate<? super T, ? super T> isDominator) { return Collector.of(ArrayList::new, (acc, t) -> { if (acc.isEmpty() || !isDominator.test(acc.get(acc.size() - 1), t)) acc.add(t); }, (acc1, acc2) -> { if (acc1.isEmpty()) return acc2; int i = 0, l = acc2.size(); T last = acc1.get(acc1.size() - 1); while (i < l && isDominator.test(last, acc2.get(i))) i++; if (i < l) acc1.addAll(acc2.subList(i, l)); return acc1; }); } /** * Returns a {@code Collector} which performs downstream reduction if all * elements satisfy the {@code Predicate}. The result is described as an * {@code Optional<R>}. * * <p> * The resulting collector returns an empty optional if at least one input * element does not satisfy the predicate. Otherwise it returns an optional * which contains the result of the downstream collector. * * <p> * This method returns a * <a href="package-summary.html#ShortCircuitReduction">short-circuiting * collector</a>: it may not process all the elements if some of items don't * satisfy the predicate or if downstream collector is a short-circuiting * collector. * * <p> * It's guaranteed that the downstream collector is not called for elements * which don't satisfy the predicate. * * @param <T> the type of input elements * @param <A> intermediate accumulation type of the downstream collector * @param <R> result type of the downstream collector * @param predicate a non-interfering, stateless predicate to checks whether * collector should proceed with element * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} witch performs downstream reduction if all * elements satisfy the predicate * @see Stream#allMatch(Predicate) * @see AbstractStreamEx#dropWhile(Predicate) * @see AbstractStreamEx#takeWhile(Predicate) */ public static <T, A, R> Collector<T, ?, Optional<R>> ifAllMatch(Predicate<T> predicate, Collector<T, A, R> downstream) { Predicate<A> finished = finished(downstream); Supplier<A> supplier = downstream.supplier(); BiConsumer<A, T> accumulator = downstream.accumulator(); BinaryOperator<A> combiner = downstream.combiner(); return new CancellableCollectorImpl<>( () -> new PairBox<>(supplier.get(), Boolean.TRUE), (acc, t) -> { if (acc.b && predicate.test(t)) { accumulator.accept(acc.a, t); } else { acc.b = Boolean.FALSE; } }, (acc1, acc2) -> { if (acc1.b && acc2.b) { acc1.a = combiner.apply(acc1.a, acc2.a); } else { acc1.b = Boolean.FALSE; } return acc1; }, acc -> acc.b ? Optional.of(downstream.finisher().apply(acc.a)) : Optional.empty(), finished == null ? acc -> !acc.b : acc -> !acc.b || finished.test(acc.a), downstream.characteristics().contains(Characteristics.UNORDERED) ? UNORDERED_CHARACTERISTICS : NO_CHARACTERISTICS); } }