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

functionalj.stream.Streamable Maven / Gradle / Ivy

// ============================================================================
// Copyright (c) 2017-2019 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.stream;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import functionalj.function.Func0;
import functionalj.function.Func1;
import functionalj.function.Func2;
import functionalj.functions.StrFuncs;
import functionalj.list.FuncList;
import functionalj.list.ImmutableList;
import functionalj.pipeable.Pipeable;
import functionalj.promise.UncompletedAction;
import functionalj.result.Result;
import functionalj.tuple.Tuple2;
import lombok.val;

class Helper {
    static  FuncList> segmentByPercentiles(FuncList list, FuncList percentiles) {
        val size    = list.size();
        val indexes = percentiles.sorted().map(d -> (int)Math.round(d*size/100)).toArrayList();
        if (indexes.get(indexes.size() - 1) != size) {
            indexes.add(size);
        }
        val lists   = new ArrayList>();
        for (int i = 0; i < indexes.size(); i++) {
            lists.add(new ArrayList());
        }
        int idx = 0;
        for (int i = 0; i < size; i++) {
            if (i >= indexes.get(idx)) {
                idx++;
            }
            val l = lists.get(idx);
            val element = list.get(i);
            l.add(element);
        }
        return FuncList.from(
                lists
                .stream()
                .map(each -> (FuncList)StreamPlus.from(each.stream()).toImmutableList()));
    }
//    
//    static  FuncList> toPercentilesOf(int size, FuncList> list) {
//        val sorted
//                = list
//                .mapWithIndex((index, tuper) -> Tuple.of(tuper._1(), tuper._2(), index*100.0/size))
//                .sortedBy(tuple -> tuple._1());
//        FuncList> results = sorted
//                .map(tuple -> Tuple.of(tuple._2(), tuple._3()));
//        return results;
//    }
}

@SuppressWarnings("javadoc")
@FunctionalInterface
public interface Streamable 
        extends
            StreamableWithMapFirst,
            StreamableWithMapThen,
            StreamableWithMapTuple,
            StreamableWithMapToMap,
            StreamableWithSplit,
            StreamableWithFillNull,
            StreamableWithSegment,
            StreamableWithCombine,
            StreamableWithCalculate,
            StreamableAddtionalOperators,
            StreamableAdditionalTerminalOperators {
    
    public static  Streamable empty() {
        return ()->StreamPlus.empty();
    }
    
    public static  Streamable emptyStreamable() {
        return ()->StreamPlus.empty();
    }
    
    @SafeVarargs
    public static  Streamable of(D ... data) {
        return ()->StreamPlus.from(Stream.of(data));
    }
    
    @SafeVarargs
    public static  Streamable steamableOf(D ... data) {
        return ()->StreamPlus.from(Stream.of(data));
    }
    
    public static  Streamable from(Collection collection) {
        return ()->StreamPlus.from(collection.stream());
    }
    
    public static  Streamable from(Func0> supplier) {
        return ()->StreamPlus.from(supplier.get());
    }
    
    @SafeVarargs
    public static  Streamable repeat(D ... data) {
        return ()->StreamPlus.repeat(data);
    }
    
    public static  StreamPlus repeat(FuncList data) {
        return ()->StreamPlus.repeat(data);
    }
    
    @SafeVarargs
    public static  Streamable cycle(D ... data) {
        return ()->StreamPlus.cycle(data);
    }
    
    public static  StreamPlus cycle(FuncList data) {
        return ()->StreamPlus.cycle(data);
    }
    
    public static Streamable loop(int time) {
        return ()->StreamPlus.loop(time);
    }
    
    public static Streamable loop() {
        return ()->StreamPlus.loop();
    }
    
    public static Streamable infiniteInt() {
        return ()->StreamPlus.infiniteInt();
    }
    
    public static Streamable range(int startInclusive, int endExclusive) {
        return ()->StreamPlus.range(startInclusive, endExclusive);
    }
    
    // Because people know this.
    @SafeVarargs
    public static  Streamable concat(Streamable ... streams) {
        return ()->StreamPlus.of(streams).flatMap(s -> s.stream());
    }
    
    // To avoid name conflict with String.concat
    @SafeVarargs
    public static  Streamable combine(Streamable ... streams) {
        return ()->StreamPlus.of(streams).flatMap(s -> s.stream());
    }
    
    public static  Streamable generate(Supplier> supplier) {
        return ()->StreamPlus.generate(supplier.get());
    }
    
    public static  Streamable generateWith(Supplier> supplier) {
        return ()->StreamPlus.generate(supplier.get());
    }
    
    public static  Streamable iterate(D seed, UnaryOperator f) {
        return ()->StreamPlus.iterate(seed, f);
    }
    
    public static  Streamable compound(D seed, UnaryOperator f) {
        return ()->StreamPlus.compound(seed, f);
    }
    
    public static  Streamable iterate(D seed1, D seed2, BinaryOperator f) {
        return ()->StreamPlus.iterate(seed1, seed2, f);
    }
    
    public static  Streamable compound(D seed1, D seed2, BinaryOperator f) {
        return ()->StreamPlus.compound(seed1, seed2, f);
    }
    
    public static  Streamable> zipOf(
            Streamable stream1, 
            Streamable stream2) {
        return ()->{
            return StreamPlus.zipOf(
                    stream1.stream(),
                    stream2.stream());
        };
    }
    
    public static  Streamable zipOf(
            Streamable   stream1, 
            Streamable   stream2,
            Func2 merger) {
        return ()->{
            return StreamPlus.zipOf(
                    stream1.stream(),
                    stream2.stream(),
                    merger);
        };
    }
    
    public static  Streamable with(
            Streamable                  source, 
            Function, Stream> action) {
        return new Streamable() {
            @Override
            public StreamPlus stream() {
                val sourceStream = source.stream();
                val targetStream = action.apply(sourceStream);
                return StreamPlus.from(targetStream);
            }
        };
    }
    public static  Streamable from(
            Streamable                      source, 
            Function, Stream> action) {
        return new Streamable() {
            @Override
            public StreamPlus stream() {
                val targetStream = action.apply(source);
                return StreamPlus.from(targetStream);
            }
        };
    }
    
    //== Stream ==
    
    public StreamPlus stream();
    
    //== Helper functions ==
    
    public default  Streamable deriveWith(Function, Stream> action) {
        return Streamable.with(this, action);
    }
    
    public default  Streamable deriveFrom(Function, Stream> action) {
        return Streamable.from(this, action);
    }
    
    //== Stream sepecific ==
    
    public default Streamable sequential() {
        return deriveWith(stream -> { 
            return stream.sequential();
        });
    }
    
    public default Streamable parallel() {
        return deriveWith(stream -> { 
            return stream.parallel();
        });
    } 
    
    public default Streamable unordered() {
        return deriveWith(stream -> { 
            return stream.unordered();
        });
    }
    
    //== Functionalities ==
    
    public default IntStreamPlus mapToInt(ToIntFunction mapper) {
        return IntStreamPlus.from(stream().mapToInt(mapper));
    }
    
    public default LongStreamPlus mapToLong(ToLongFunction mapper) {
        return stream().mapToLong(mapper);
    }
    
    public default DoubleStreamPlus mapToDouble(ToDoubleFunction mapper) {
        return stream().mapToDouble(mapper);
    }
    
    public default IntStreamPlus flatMapToInt(Function mapper) {
        return IntStreamPlus.from(stream().flatMapToInt(mapper));
    }
    
    public default LongStreamPlus flatMapToLong(Function mapper) {
        return stream().flatMapToLong(mapper);
    }
    
    public default DoubleStreamPlus flatMapToDouble(Function mapper) {
        return stream().flatMapToDouble(mapper);
    }
    
    public default  Streamable map(Function mapper) {
        return deriveWith(stream -> {
            return stream.map(mapper);
        });
    }
    
    public default  Streamable flatMap(Function> mapper) {
        return deriveWith(stream -> {
            return stream.flatMap(e -> mapper.apply(e).stream());
        });
    }
    
    public default Streamable filter(Predicate predicate) {
        return deriveWith(stream -> {
            return (predicate == null)
                ? stream
                : stream.filter(predicate);
        });
    }
    
    public default Streamable peek(Consumer action) {
        return deriveWith(stream -> {
            return (action == null)
                    ? stream
                    : stream.peek(action);
        });
    }
    
    //-- Limit/Skip --
    
    public default Streamable limit(long maxSize) {
        return deriveWith(stream -> {
            return stream.limit(maxSize);
        });
    }
    
    public default Streamable skip(long n) {
        return deriveWith(stream -> {
            return stream.skip(n);
        });
    }
    
    public default Streamable limit(Long maxSize) {
        return deriveWith(stream -> {
            return ((maxSize == null) || (maxSize.longValue() < 0))
                    ? stream
                    : stream.limit(maxSize);
        });
    }
    
    public default Streamable skip(Long startAt) {
        return deriveWith(stream -> {
            return ((startAt == null) || (startAt.longValue() < 0))
                    ? stream
                    : stream.skip(startAt);
        });
    }
    
    public default Streamable skipWhile(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).skipWhile(condition);
        });
    }
    
    public default Streamable skipUntil(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).skipUntil(condition);
        });
    }
    
    public default Streamable takeWhile(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).takeWhile(condition);
        });
    }
    
    public default Streamable takeUntil(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).takeUntil(condition);
        });
    }
    
    public default Streamable distinct() {
        return deriveWith(stream -> {
            return stream.distinct();
        });
    }
    
    //-- Sorted --
    
    public default Streamable sorted() {
        return deriveWith(stream -> {
            return stream.sorted();
        });
    }
    
    public default Streamable sorted(
            Comparator comparator) {
        return deriveWith(stream -> {
            return (comparator == null)
                    ? stream.sorted()
                    : stream.sorted(comparator);
        });
    }
    
    public default > Streamable sortedBy(
            Function mapper) {
        return deriveWith(stream -> {
            return stream.sorted((a, b) -> {
                        T vA = mapper.apply(a);
                        T vB = mapper.apply(b);
                        return vA.compareTo(vB);
                    });
        });
    }
    
    public default  Streamable sortedBy(
            Function mapper, 
            Comparator             comparator) {
        return deriveWith(stream -> {
            return stream.sorted((a, b) -> {
                    T vA = mapper.apply(a);
                    T vB = mapper.apply(b);
                    return Objects.compare(vA,  vB, comparator);
                });
        });
    }
    
    //-- Terminate --
    
    public default void forEach(Consumer action) {
        if (action == null)
            return;
        
        stream().forEach(action);
    }
    
    public default void forEachOrdered(Consumer action) {
        if (action == null)
            return;
        
        stream().forEachOrdered(action);
    }
    
    public default DATA reduce(DATA identity, BinaryOperator accumulator) {
        return stream().reduce(identity, accumulator);
    }
    
    public default Optional reduce(BinaryOperator accumulator) {
        return stream().reduce(accumulator);
    }
    
    public default  U reduce(
                    U                              identity,
                    BiFunction accumulator,
                    BinaryOperator              combiner) {
        return stream().reduce(identity, accumulator, combiner);
    }
    
    public default  R collect(
            Collector collector) {
        return stream().collect(collector);
    }
    
    public default  R collect(
            Supplier                 supplier,
            BiConsumer accumulator,
            BiConsumer            combiner) {
        return stream().collect(supplier, accumulator, combiner);
    }
    
    public default Optional min(
            Comparator comparator) {
        return stream().min(comparator);
    }
    
    public default Optional max(
            Comparator comparator) {
        return stream().max(comparator);
    }
    
    public default long count() {
        return stream().count();
    }
    
    public default int size() {
        return (int)stream().count();
    }
    
    public default boolean anyMatch(
            Predicate predicate) {
        return stream().anyMatch(predicate);
    }
    
    public default boolean allMatch(
            Predicate predicate) {
        return stream().allMatch(predicate);
    }
    
    public default boolean noneMatch(
            Predicate predicate) {
        return stream().noneMatch(predicate);
    }
    
    public default Optional findFirst() {
        return stream().findFirst();
    }
    
    public default Optional findAny() {
        return stream().findAny();
    }
    
    //== toXXX ===
    
    public default Object[] toArray() {
        return stream().toArray();
    }
    
    public default  T[] toArray(T[] a) {
        return StreamPlus.of(stream()).toJavaList().toArray(a);
    }
    
    public default  A[] toArray(IntFunction generator) {
        return stream().toArray(generator);
    }
    
    public default List toJavaList() {
        return stream().collect(Collectors.toList());
    }
    
    public default byte[] toByteArray(Func1 toByte) {
        val byteArray = new ByteArrayOutputStream();
        stream().forEach(d -> byteArray.write(toByte.apply(d)));
        return byteArray.toByteArray();
    }
    
    public default int[] toIntArray(ToIntFunction toInt) {
        return mapToInt(toInt).toArray();
    }
    
    public default long[] toLongArray(ToLongFunction toLong) {
        return mapToLong(toLong).toArray();
    }
    
    public default double[] toDoubleArray(ToDoubleFunction toDouble) {
        return mapToDouble(toDouble).toArray();
    }
    
    public default FuncList toList() {
        return toImmutableList();
    }
    
    public default FuncList toLazyList() {
        return FuncList.from(this);
    }
    
    public default String toListString() {
        return "[" + map(String::valueOf).collect(Collectors.joining(", ")) + "]";
    }
    
    public default ImmutableList toImmutableList() {
        return ImmutableList.from(stream());
    }
    
    public default List toMutableList() {
        return toArrayList();
    }
    
    public default ArrayList toArrayList() {
        return new ArrayList(toJavaList());
    }
    
    public default Set toSet() {
        return new HashSet(stream().collect(Collectors.toSet()));
    }
    
    //-- Iterator --
    
    public default IteratorPlus iterator() {
        return IteratorPlus.from(stream());
    }
    
    public default Spliterator spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
    
    //== Plus ==
    
    public default String joinToString() {
        return map(StrFuncs::toStr)
                .collect(Collectors.joining());
    }
    public default String joinToString(String delimiter) {
        return map(StrFuncs::toStr)
                .collect(Collectors.joining(delimiter));
    }
    
    //++ Plus w/ Self ++
    
    public default  Pipeable> pipable() {
        return Pipeable.of(this);
    }
    
    public default  T pipe(Function, T> piper) {
        return piper.apply(this);
    }
    
    //== Spawn ==
    
    
    public default  Streamable> spawn(Func1> mapper) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream()).spawn(mapper);
        });
    }
    
    //== accumulate + restate ==
    
    public default Streamable accumulate(BiFunction accumulator) {
        return deriveWith(stream -> {
            val iterator = StreamPlus.from(stream).iterator();
            if (!iterator.hasNext())
                return StreamPlus.empty();
            
            val prev = new AtomicReference(iterator.next());
            return StreamPlus.concat(
                        StreamPlus.of(prev.get()),
                        iterator.stream().map(n -> {
                            val next = accumulator.apply(n, prev.get());
                            prev.set(next);
                            return next;
                        })
                    );
        });
    }
    
    public default Streamable restate(BiFunction, Streamable> restater) {
        val func = (UnaryOperator>>)((Tuple2> pair) -> {
            val stream   = pair._2();
            val iterator = stream.iterator();
            if (!iterator.hasNext())
                return null;
            
            val head = iterator.next();
            val tail =restater.apply(head, ()->iterator.stream());
            return Tuple2.of(head, tail);
        });
        val seed = Tuple2.of((DATA)null, this);
        val endStream = (Streamable)(()->StreamPlus.iterate(seed, func).takeUntil(t -> t == null).skip(1).map(t -> t._1()));
        return endStream;
    }
    
//    
//    public default > FuncList> toPercentilesOf(Function mapper) {
//        FuncList> list 
//                = mapWithIndex(Tuple2::of)
//                .sortedBy(tuple -> mapper.apply(tuple._2()))
//                .toImmutableList();
//        return Helper.toPercentilesOf(size() - 1, list);
//    }
//    
//    public default  FuncList> toPercentilesOf(Function mapper, Comparator comparator) {
//        FuncList> list 
//                = mapWithIndex(Tuple2::of)
//                .sortedBy(tuple -> mapper.apply(tuple._2()), comparator)
//                .toImmutableList();
//        return Helper.toPercentilesOf(size() - 1, list);
//    }
    
}