All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.scr.j8iterables.J8Iterables Maven / Gradle / Ivy

There is a newer version: 1.8.0
Show newest version
package com.github.scr.j8iterables;

import com.github.scr.j8iterables.core.ConsumingIdentity;
import com.github.scr.j8iterables.core.StreamIterable;
import com.google.common.collect.FluentIterable;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Optional;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Utility methods to extend Guava Iterables with Java 8 Stream-like classes such as Collectors.
 *
 * @author scr
 */
public class J8Iterables {
    /**
     * Collect iterable of iterables into a mutable container.
     *
     * @param iterables   The iterable of iterables
     * @param supplier    The container supplier
     * @param accumulator The accumulator function
     * @param combiner    The combiner function
     * @param          The type of elements
     * @param          The return type
     * @return Collected result
     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
     */
    public static  R collect(@NotNull Iterable> iterables,
                                   @NotNull Supplier supplier,
                                   @NotNull BiConsumer accumulator,
                                   @NotNull BiConsumer combiner) {
        R result = supplier.get();
        for (Iterable iterable : iterables) {
            R innerResult = supplier.get();
            for (T element : iterable) {
                accumulator.accept(innerResult, element);
            }
            combiner.accept(result, innerResult);
        }
        return result;
    }

    /**
     * Collect iterable into a mutable container.
     *
     * @param iterable  The iterable
     * @param collector The collector object
     * @param        The type of elements
     * @param        The type of accumulator
     * @param        The return type
     * @return Collected result
     * @see Stream#collect(Collector)
     */
    public static  R collect(@NotNull Iterable iterable, @NotNull Collector collector) {
        A container = collector.supplier().get();
        BiConsumer accumulator = collector.accumulator();
        for (T t : iterable) {
            accumulator.accept(container, t);
        }
        return collector.finisher().apply(container);
    }

    /**
     * Perform a reduction on iterable.
     *
     * @param iterable    The iterable
     * @param accumulator The accumulator function
     * @param          The type of elements
     * @return The reduced result
     * @see Stream#reduce(BinaryOperator)
     */
    public static  Optional reduce(@NotNull Iterable iterable, @NotNull BinaryOperator accumulator) {
        boolean foundAny = false;
        T result = null;
        for (T element : iterable) {
            if (!foundAny) {
                foundAny = true;
                result = element;
            } else {
                result = accumulator.apply(result, element);
            }
        }
        return foundAny ? Optional.of(result) : Optional.empty();
    }

    /**
     * Perform a reduction on an iterable.
     *
     * @param iterable    The iterable
     * @param identity    The identity to start reduction with
     * @param accumulator The accumulator function
     * @param          The type of elements
     * @return The reduced result
     * @see Stream#reduce(Object, BinaryOperator)
     */
    public static  T reduce(@NotNull Iterable iterable,
                               T identity,
                               @NotNull BinaryOperator accumulator) {
        T result = identity;
        for (T element : iterable) {
            result = accumulator.apply(result, element);
        }
        return result;
    }

    /**
     * Perform a reduction on an iterable of iterables.
     *
     * @param iterables   An iterator of iterables.
     * @param identity    The identity to start reduction with
     * @param accumulator The accumulator function
     * @param combiner    The combiner function
     * @param          The type of elements
     * @param          The reduced type
     * @return The reduced result
     * @see Stream#reduce(Object, BiFunction, BinaryOperator)
     */
    public static  U reduce(@NotNull Iterable> iterables,
                                  U identity,
                                  @NotNull BiFunction accumulator,
                                  @NotNull BinaryOperator combiner) {
        U result = identity;
        for (Iterable iterable : iterables) {
            U innerResult = identity;
            for (T element : iterable) {
                innerResult = accumulator.apply(innerResult, element);
            }
            result = combiner.apply(result, innerResult);
        }
        return result;
    }

    /**
     * Peek at the iterable without modifying the result.
     *
     * @param iterable The iterable to peek at
     * @param consumer The peeking function
     * @param       The type of elements
     * @return an Iterable that, when traversed will invoke the consumer on each element
     * @see Stream#peek(Consumer)
     */
    @NotNull
    public static  FluentIterable peek(@NotNull Iterable iterable, @NotNull Consumer consumer) {
        return FluentIterable.from(iterable).transform(peeker(consumer));
    }

    /**
     * Return a peeking transformer - a UnaryOperator that will send each element to the consumer and return identity.
     *
     * @param consumer The peeking function
     * @param       The type of elements
     * @return a peeking (non-transforming) transformer
     */
    @NotNull
    public static  ConsumingIdentity peeker(@NotNull Consumer consumer) {
        return new ConsumingIdentity<>(consumer);
    }

    /**
     * Create a one-time Iterable from a Stream.
     *
     * @param stream The Stream to use in creating an Iterable
     * @param     The type of elements
     * @return Iterable from the given stream
     */
    @NotNull
    public static  FluentIterable fromStream(@NotNull Stream stream) {
        return new StreamIterable<>(stream);
    }

    /**
     * Create a Stream from the given Iterable.
     *
     * @param iterable The Iterable to use in creating a Stream
     * @param       The type of elements
     * @return Stream from the given iterable
     */
    @NotNull
    public static  Stream toStream(@NotNull Iterable iterable) {
        if (iterable instanceof Collection) {
            return ((Collection) iterable).stream();
        }
        // TODO(scr): Is it possible to do late-binding (iterable::spliterator)? Need to know characteristics.
        return StreamSupport.stream(iterable.spliterator(), false);
    }
}