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

functionalj.stream.Streamable Maven / Gradle / Ivy

There is a newer version: 1.0.17
Show newest version
// ============================================================================
// 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 static functionalj.function.Func.themAll;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
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.AtomicInteger;
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.function.Func3;
import functionalj.function.Func4;
import functionalj.function.Func5;
import functionalj.function.Func6;
import functionalj.functions.StrFuncs;
import functionalj.lens.lenses.AnyLens;
import functionalj.list.FuncList;
import functionalj.list.ImmutableList;
import functionalj.map.FuncMap;
import functionalj.map.ImmutableMap;
import functionalj.pipeable.Pipeable;
import functionalj.promise.UncompleteAction;
import functionalj.result.Result;
import functionalj.tuple.Tuple;
import functionalj.tuple.Tuple2;
import functionalj.tuple.Tuple3;
import functionalj.tuple.Tuple4;
import functionalj.tuple.Tuple5;
import functionalj.tuple.Tuple6;
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 StreamableWithGet {
    
    @SafeVarargs
    public static  Streamable of(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 cycle(D ... 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);
    }
    
    public static  Streamable empty() {
        return ()->StreamPlus.empty();
    }
    
    // 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 generateBy(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 ()->{
            AtomicInteger      counter = new AtomicInteger(0);
            AtomicReference d1      = new AtomicReference(seed1);
            AtomicReference d2      = new AtomicReference(seed2);
            return StreamPlus.generate(()->{
                if (counter.getAndIncrement() == 0)
                    return seed1;
                if (counter.getAndIncrement() == 2)
                    return seed2;
                
                D i2 = d2.get();
                D i1 = d1.getAndSet(i2);
                D i  = f.apply(i1, i2);
                d2.set(i);
                return i;
            });
        };
    }
    
    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);
            }
        };
    }
    
    public StreamPlus stream();
    
    public default  Streamable deriveWith(Function, Stream> action) {
        return Streamable.with(this, action);
    }
    
    public default  Streamable deriveFrom(Function, Stream> action) {
        return Streamable.from(this, action);
    }
    
    public default  Pipeable> pipable() {
        return Pipeable.of(this);
    }
    
    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 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();
        });
    }
    
    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 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);
        });
    }
    
    //-- Sorted --
    
    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);
                });
        });
    }
    
    // -- fillNull --
    
    public default  Streamable fillNull(AnyLens lens, VALUE replacement) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(lens, replacement));
    }
    
    public default  Streamable fillNull(
            Func1       get, 
            Func2 set, 
            VALUE                    replacement) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(get, set, replacement));
    }
    
    public default  Streamable fillNull(
            AnyLens lens, 
            Supplier      replacementSupplier) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(lens, replacementSupplier));
    }
    
    public default  Streamable fillNull(
            Func1       get, 
            Func2 set, 
            Supplier          replacementSupplier) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(get, set, replacementSupplier));
    }
    
    public default  Streamable fillNull(
            AnyLens lens, 
            Func1   replacementFunction) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(lens, replacementFunction));
    }
    
    public default  Streamable fillNull(
            Func1       get, 
            Func2 set, 
            Func1       replacementFunction) {
        return deriveWith(stream -> StreamPlus.from(stream).fillNull(get, set, replacementFunction));
    }
    
    //--map with condition --
    
    public default Streamable mapOnly(Predicate checker, Function mapper) {
        return map(d -> checker.test(d) ? mapper.apply(d) : d);
    }
    
    public default  Streamable mapIf(
            Predicate   checker, 
            Function mapper, 
            Function elseMapper) {
        return deriveWith(stream -> StreamPlus.from(stream).mapIf(checker, mapper, elseMapper));
    }
    
    public default  Streamable mapFirst(
            Function mapper1,
            Function mapper2) {
        return deriveWith(stream -> StreamPlus.from(stream).mapFirst(mapper1, mapper2));
    }
    
    public default  Streamable mapFirst(
            Function mapper1,
            Function mapper2,
            Function mapper3) {
        return deriveWith(stream -> StreamPlus.from(stream).mapFirst(mapper1, mapper2, mapper3));
    }
    
    public default  Streamable mapFirst(
            Function mapper1,
            Function mapper2,
            Function mapper3,
            Function mapper4) {
        return deriveWith(stream -> StreamPlus.from(stream).mapFirst(mapper1, mapper2, mapper3, mapper4));
    }
    
    public default  Streamable mapFirst(
            Function mapper1,
            Function mapper2,
            Function mapper3,
            Function mapper4,
            Function mapper5) {
        return deriveWith(stream -> StreamPlus.from(stream).mapFirst(mapper1, mapper2, mapper3, mapper4, mapper5));
    }
    
    public default  Streamable mapFirst(
            Function mapper1,
            Function mapper2,
            Function mapper3,
            Function mapper4,
            Function mapper5,
            Function mapper6) {
        return deriveWith(stream -> StreamPlus.from(stream).mapFirst(mapper1, mapper2, mapper3, mapper4, mapper5, mapper6));
    }
    
    //-- mapWithIndex --
    
    public default Streamable> mapWithIndex() {
        val index = new AtomicInteger();
        return map(each -> Tuple2.of(index.getAndIncrement(), each));
    }
    
    public default  Streamable mapWithIndex(BiFunction mapper) {
        return deriveWith(stream -> {
            val index = new AtomicInteger();
            return stream.map(each -> mapper.apply(index.getAndIncrement(), each));
        });
    }
    
    public default  Streamable mapWithIndex(
                Function       mapper1,
                BiFunction mapper) {
        return deriveWith(stream -> {
            val index = new AtomicInteger();
            return stream.map(each -> mapper.apply(
                                    index.getAndIncrement(),
                                    mapper1.apply(each)));
        });
    }
    
    //-- mapWithPrev --
    
    public default  Streamable mapWithPrev(BiFunction, ? super DATA, ? extends TARGET> mapper) {
        return deriveWith(stream -> {
            val prev = new AtomicReference>(Result.ofNotExist());
            return map(element -> {
                val newValue = mapper.apply(prev.get(), element);
                prev.set(Result.valueOf(element));
                return newValue;
            })
            .stream();
        });
    }
    
    // -- accumulate --
    
    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;
    }
    
    //== Map to tuple. ==
    // ++ Generated with: GeneratorFunctorMapToTupleToObject ++
    
    public default  
        Streamable> mapTuple(
                Function mapper1,
                Function mapper2) {
        return mapThen(mapper1, mapper2,
                   (v1, v2) -> Tuple2.of(v1, v2));
    }
    
    public default  
        Streamable> mapTuple(
                Function mapper1,
                Function mapper2,
                Function mapper3) {
        return mapThen(mapper1, mapper2, mapper3,
                   (v1, v2, v3) -> Tuple3.of(v1, v2, v3));
    }
    
    public default  
        Streamable> mapTuple(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4) {
        return mapThen(mapper1, mapper2, mapper3, mapper4,
                   (v1, v2, v3, v4) -> Tuple4.of(v1, v2, v3, v4));
    }
    
    public default  
        Streamable> mapTuple(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4,
                Function mapper5) {
        return mapThen(mapper1, mapper2, mapper3, mapper4, mapper5,
                   (v1, v2, v3, v4, v5) -> Tuple5.of(v1, v2, v3, v4, v5));
    }
    public default  
        Streamable> mapTuple(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4,
                Function mapper5,
                Function mapper6) {
        return mapThen(mapper1, mapper2, mapper3, mapper4, mapper5, mapper6,
                   (v1, v2, v3, v4, v5, v6) -> Tuple6.of(v1, v2, v3, v4, v5, v6));
    }
    
    //-- Map and combine --
    
    public default  
        Streamable mapThen(
                Function mapper1,
                Function mapper2,
                BiFunction function) {
        return map(each -> {
            val v1 = mapper1.apply(each);
            val v2 = mapper2.apply(each);
            val v  = function.apply(v1, v2);
            return v;
        });
    }
    public default  
        Streamable mapThen(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Func3 function) {
        return map(each -> {
            val v1 = mapper1.apply(each);
            val v2 = mapper2.apply(each);
            val v3 = mapper3.apply(each);
            val v  = function.apply(v1, v2, v3);
            return v;
        });
    }
    public default  
        Streamable mapThen(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4,
                Func4 function) {
        return map(each -> {
            val v1 = mapper1.apply(each);
            val v2 = mapper2.apply(each);
            val v3 = mapper3.apply(each);
            val v4 = mapper4.apply(each);
            val v  = function.apply(v1, v2, v3, v4);
            return v;
        });
    }
    public default  
        Streamable mapThen(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4,
                Function mapper5,
                Func5 function) {
        return map(each -> {
            val v1 = mapper1.apply(each);
            val v2 = mapper2.apply(each);
            val v3 = mapper3.apply(each);
            val v4 = mapper4.apply(each);
            val v5 = mapper5.apply(each);
            val v  = function.apply(v1, v2, v3, v4, v5);
            return v;
        });
    }
    public default  
        Streamable mapThen(
                Function mapper1,
                Function mapper2,
                Function mapper3,
                Function mapper4,
                Function mapper5,
                Function mapper6,
                Func6 function) {
        return map(each -> {
            val v1 = mapper1.apply(each);
            val v2 = mapper2.apply(each);
            val v3 = mapper3.apply(each);
            val v4 = mapper4.apply(each);
            val v5 = mapper5.apply(each);
            val v6 = mapper6.apply(each);
            val v  = function.apply(v1, v2, v3, v4, v5, v6);
            return v;
        });
    }
    
    // -- Generated with: GeneratorFunctorMapToTupleToObject --
    
    public default  Streamable> mapToMap(
            KEY key, Function mapper) {
        return map(data -> ImmutableMap.of(key, mapper.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5,
            KEY key6, Function mapper6) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data),
                key6, mapper6.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5,
            KEY key6, Function mapper6,
            KEY key7, Function mapper7) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data),
                key6, mapper6.apply(data),
                key7, mapper7.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5,
            KEY key6, Function mapper6,
            KEY key7, Function mapper7,
            KEY key8, Function mapper8) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data),
                key6, mapper6.apply(data),
                key7, mapper7.apply(data),
                key8, mapper8.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5,
            KEY key6, Function mapper6,
            KEY key7, Function mapper7,
            KEY key8, Function mapper8,
            KEY key9, Function mapper9) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data),
                key6, mapper6.apply(data),
                key7, mapper7.apply(data),
                key8, mapper8.apply(data),
                key9, mapper9.apply(data)));
    }
    
    public default  Streamable> mapToMap(
            KEY key1, Function mapper1,
            KEY key2, Function mapper2,
            KEY key3, Function mapper3,
            KEY key4, Function mapper4,
            KEY key5, Function mapper5,
            KEY key6, Function mapper6,
            KEY key7, Function mapper7,
            KEY key8, Function mapper8,
            KEY key9, Function mapper9,
            KEY key10, Function mapper10) {
        return map(data -> ImmutableMap.of(
                key1, mapper1.apply(data),
                key2, mapper2.apply(data),
                key3, mapper3.apply(data),
                key4, mapper4.apply(data),
                key5, mapper5.apply(data),
                key6, mapper6.apply(data),
                key7, mapper7.apply(data),
                key8, mapper8.apply(data),
                key9, mapper9.apply(data),
                key10, mapper10.apply(data)));
    }
    
    //-- Filter --
    
    public default Streamable filterNonNull() {
        return deriveWith(stream -> stream.filter(Objects::nonNull));
    }
    
    public default Streamable filterIn(Collection collection) {
        return deriveWith(stream -> {
            return (collection == null)
                ? Stream.empty()
                : stream.filter(data -> collection.contains(data));
        });
    }
    
    public default Streamable exclude(Predicate predicate) {
        return deriveWith(stream -> {
            return (predicate == null)
                ? stream
                : stream.filter(data -> !predicate.test(data));
        });
    }
    
    public default Streamable excludeIn(Collection collection) {
        return deriveWith(stream -> {
            return (collection == null)
                ? stream
                : stream.filter(data -> !collection.contains(data));
        });
    }
    
    public default  Streamable filter(Class clzz) {
        return filter(clzz::isInstance);
    }
    
    public default  Streamable filter(Class clzz, Predicate theCondition) {
        return filter(value -> {
            if (!clzz.isInstance(value))
                return false;
            
            val target = clzz.cast(value);
            val isPass = theCondition.test(target);
            return isPass;
        });
    }
    
    public default  Streamable filter(Function mapper, Predicate theCondition) {
        return filter(value -> {
            val target = mapper.apply(value);
            val isPass = theCondition.test(target);
            return isPass;
        });
    }

    public default Streamable filterWithIndex(BiFunction predicate) {
        val index = new AtomicInteger();
        return filter(each -> {
                    return (predicate != null) 
                            && predicate.apply(index.getAndIncrement(), each);
        });
    }
    
    //-- Peek --
    
    public default  Streamable peek(Class clzz, Consumer theConsumer) {
        return peek(value -> {
            if (!clzz.isInstance(value))
                return;
            
            val target = clzz.cast(value);
            theConsumer.accept(target);
        });
    }
    public default Streamable peek(Predicate selector, Consumer theConsumer) {
        return peek(value -> {
            if (!selector.test(value))
                return;
            
            theConsumer.accept(value);
        });
    }
    public default  Streamable peek(Function mapper, Consumer theConsumer) {
        return peek(value -> {
            val target = mapper.apply(value);
            theConsumer.accept(target);
        });
    }
    
    public default  Streamable peek(Function mapper, Predicate selector, Consumer theConsumer) {
        return peek(value -> {
            val target = mapper.apply(value);
            if (selector.test(target))
                theConsumer.accept(target);
        });
    }
    
    //-- FlatMap --
    
    public default Streamable flatMapOnly(Predicate checker, Function> mapper) {
        return flatMap(d -> checker.test(d) ? mapper.apply(d) :()-> StreamPlus.of(d));
    }
    public default  Streamable flatMapIf(
            Predicate checker, 
            Function> mapper, 
            Function> elseMapper) {
        return flatMap(d -> checker.test(d) ? mapper.apply(d) : elseMapper.apply(d));
    }
    
    //-- segment --
    
    public default Streamable> segment(int count) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(count);
        });
    }
    public default Streamable> segment(int count, boolean includeTail) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(count, includeTail);
        });
    }
    public default Streamable> segment(Predicate startCondition) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(startCondition);
        });
    }
    public default Streamable> segment(Predicate startCondition, boolean includeTail) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(startCondition, includeTail);
        });
    }
    
    public default Streamable> segment(Predicate startCondition, Predicate endCondition) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(startCondition, endCondition);
        });
    }
    
    public default Streamable> segment(Predicate startCondition, Predicate endCondition, boolean includeLast) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).segment(startCondition, endCondition, includeLast);
        });
    }
    
    public default  Streamable> segmentByPercentiles(int ... percentiles) {
        val percentileList = IntStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(percentileList);
    }
    
    public default  Streamable> segmentByPercentiles(double ... percentiles) {
        val percentileList = DoubleStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(percentileList);
    }
    
    public default  FuncList> segmentByPercentiles(FuncList percentiles) {
        val list = sorted().toImmutableList();
        return Helper.segmentByPercentiles(list, percentiles);
    }
    
    public default > FuncList> segmentByPercentiles(Function mapper, int ... percentiles) {
        val percentileList = IntStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(mapper, percentileList);
    }
    
    public default  FuncList> segmentByPercentiles(Function mapper, Comparator comparator, int ... percentiles) {
        val percentileList = IntStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(mapper, comparator, percentileList);
    }
    
    public default > FuncList> segmentByPercentiles(Function mapper, double ... percentiles) {
        val percentileList = DoubleStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(mapper, percentileList);
    }
    
    public default  FuncList> segmentByPercentiles(Function mapper, Comparator comparator, double ... percentiles) {
        val percentileList = DoubleStreamPlus.of(percentiles).mapToObj(Double::valueOf).toImmutableList();
        return segmentByPercentiles(mapper, comparator, percentileList);
    }
    
    public default > FuncList> segmentByPercentiles(Function mapper, FuncList percentiles) {
        val list = sortedBy(mapper).toImmutableList();
        return Helper.segmentByPercentiles(list, percentiles);
    }
    
    public default  FuncList> segmentByPercentiles(Function mapper, Comparator comparator, FuncList percentiles) {
        val list = sortedBy(mapper, comparator).toImmutableList();
        return Helper.segmentByPercentiles(list, percentiles);
    }
//    
//    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);
//    }
    
    //-- Zip --
    
    public default  Streamable combine(Stream anotherStream, Func2 combinator) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).combine(anotherStream, combinator);
        });
    }
    public default  Streamable combine(Stream anotherStream, ZipWithOption option, Func2 combinator) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).combine(anotherStream, option, combinator);
        });
    }
    
    public default  Streamable> zipWith(Stream anotherStream) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).zipWith(anotherStream);
        });
    }
    public default  Streamable> zipWith(Stream anotherStream, ZipWithOption option) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).zipWith(anotherStream, option);
        });
    }
    
    public default Streamable choose(Stream anotherStream, Func2 selectThisNotAnother) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).choose(anotherStream, selectThisNotAnother);
        });
    }
    public default Streamable merge(Stream anotherStream) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream).merge(anotherStream);
        });
    }
    
    @SuppressWarnings("unchecked")
    public default Streamable concatWith(Streamable ... tails) {
        return deriveWith(stream -> {
            return StreamPlus
                    .concat(StreamPlus.of(stream), StreamPlus.of(tails).map(Streamable::stream))
                    .flatMap(themAll());
        });
    }
    
    //-- Plus w/ Self --
    //============================================================================
    
    //== Functionalities ==
    
    public default IntStreamPlus mapToInt(ToIntFunction mapper) {
        return IntStreamPlus.from(stream().mapToInt(mapper));
    }
    
    public default LongStream mapToLong(ToLongFunction mapper) {
        return stream().mapToLong(mapper);
    }
    
    public default DoubleStream mapToDouble(ToDoubleFunction mapper) {
        return stream().mapToDouble(mapper);
    }
    
    public default IntStream flatMapToInt(Function mapper) {
        return IntStreamPlus.from(stream().flatMapToInt(mapper));
    }
    
    public default LongStream flatMapToLong(Function mapper) {
        return stream().flatMapToLong(mapper);
    }
    
    public default DoubleStream flatMapToDouble(Function mapper) {
        return stream().flatMapToDouble(mapper);
    }
    
    public default void forEach(Consumer action) {
        if (action == null)
            return;
        
        stream().forEach(action);
    }
    
    public default void forEachWithIndex(BiConsumer action) {
        if (action == null)
            return;
        
        val index = new AtomicInteger();
        stream().forEach(each ->
                    action.accept(index.getAndIncrement(), each));
    }
    
    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(
                    Supplier                 supplier,
                    BiConsumer accumulator,
                    BiConsumer            combiner) {
        return stream().collect(supplier, accumulator, combiner);
    }
    
    public default  R collect(Collector collector) {
        return stream().collect(collector);
    }
    
    public default Optional min(Comparator comparator) {
        return stream().min(comparator);
    }
    
    public default Optional max(Comparator comparator) {
        return stream().max(comparator);
    }
    
    public default > Optional minBy(Func1 mapper) {
        return stream().min((a,b)->mapper.apply(a).compareTo(mapper.apply(b)));
    }
    
    public default > Optional maxBy(Func1 mapper) {
        return stream().max((a,b)->mapper.apply(a).compareTo(mapper.apply(b)));
    }
    
    public default Optional sumToBigDecimal(Function toBigDecimal) {
        return map(toBigDecimal).reduce(BigDecimal::add);
    }
    
    public default Optional minToBigDecimal(Function toBigDecimal) {
        return map(toBigDecimal).reduce((a, b) -> a.compareTo(b) <= 0 ? a : b);
    }
    
    public default Optional maxToBigDecimal(Function toBigDecimal) {
        return map(toBigDecimal).reduce((a, b) -> a.compareTo(b) <= 0 ? b : a);
    }
    
    public default Optional averageToBigDecimal(Function toBigDecimal) {
        val countSum = map(each -> Tuple.of(1, toBigDecimal.apply(each)))
        .reduce((a, b)->Tuple.of(a._1 + b._1, a._2.add(b._2)));
        return countSum.map(t -> t._2.divide(new BigDecimal(t._1)));
    }
    
    public default Optional sum(Function toBigDecimal) {
        return sumToBigDecimal(toBigDecimal);
    }
    
    public default Optional min(Function toBigDecimal) {
        return minToBigDecimal(toBigDecimal);
    }
    
    public default Optional max(Function toBigDecimal) {
        return maxToBigDecimal(toBigDecimal);
    }
    
    public default Optional average(Function toBigDecimal) {
        return averageToBigDecimal(toBigDecimal);
    }
    
    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(Predicate predicate) {
        return stream().filter(predicate).findFirst();
    }
    
    public default Optional findAny(Predicate predicate) {
        return stream().filter(predicate).findAny();
    }
    
    public default  Optional findFirst(Function mapper, Predicate theCondition) {
        return filter(mapper, theCondition).findFirst();
    }
    
    public default   Optional findAny(Function mapper, Predicate theCondition) {
        return filter(mapper, theCondition).findAny();
    }
    
    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 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()));
    }
    
    public default IteratorPlus iterator() {
        return IteratorPlus.from(stream());
    }
    
    public default Spliterator spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
    
    public default  FuncMap> groupingBy(Function classifier) {
        val theMap = new HashMap>();
        stream()
            .collect(Collectors.groupingBy(classifier))
            .forEach((key,list)->theMap.put(key, ImmutableList.from(list)));
        return ImmutableMap.from(theMap);
    }
    
    @SuppressWarnings("unchecked")
    public default  FuncMap toMap(Function keyMapper) {
        val theMap = stream().collect(Collectors.toMap(keyMapper, data -> data));
        return (FuncMap)ImmutableMap.from(theMap);
    }
    
    @SuppressWarnings("unchecked")
    public default  FuncMap toMap(
                Function  keyMapper,
                Function valueMapper) {
        val theMap = stream().collect(Collectors.toMap(keyMapper, valueMapper));
        return (FuncMap) ImmutableMap.from(theMap);
    }
    
    @SuppressWarnings("unchecked")
    public default  FuncMap toMap(
                Function   keyMapper,
                Function valueMapper,
                BinaryOperator mergeFunction) {
        val theMap = stream().collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction));
        return (FuncMap) ImmutableMap.from(theMap);
    }
    
    //== 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));
    }
    
    //-- Split --
    
    public default Tuple2, FuncList> split(
            Predicate predicate) {
        val temp = this.mapTuple(
                it -> predicate.test(it) ? 0 : 1,
                it -> it
        ).toList();
        val list1 = temp.filter(it -> it._1() == 0).map(it -> it._2());
        val list2 = temp.filter(it -> it._1() == 1).map(it -> it._2());
        return Tuple.of(
                list1,
                list2
        );
    }
    
    public default Tuple3, FuncList, FuncList> split(
            Predicate predicate1,
            Predicate predicate2) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    :                       2,
                it -> it
        ).toImmutableList();
        val list1 = temp.filter(it -> it._1() == 0).map(it -> it._2());
        val list2 = temp.filter(it -> it._1() == 1).map(it -> it._2());
        val list3 = temp.filter(it -> it._1() == 2).map(it -> it._2());
        return Tuple.of(
                list1,
                list2,
                list3
        );
    }
    
    public default Tuple4, FuncList, FuncList, FuncList> split(
            Predicate predicate1,
            Predicate predicate2,
            Predicate predicate3) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    :                       3,
                it -> it
        ).toImmutableList();
        val list1 = temp.filter(it -> it._1() == 0).map(it -> it._2());
        val list2 = temp.filter(it -> it._1() == 1).map(it -> it._2());
        val list3 = temp.filter(it -> it._1() == 2).map(it -> it._2());
        val list4 = temp.filter(it -> it._1() == 3).map(it -> it._2());
        return Tuple.of(
                list1,
                list2,
                list3,
                list4
        );
    }
    
    public default Tuple5, FuncList, FuncList, FuncList, FuncList> split(
            Predicate predicate1,
            Predicate predicate2,
            Predicate predicate3,
            Predicate predicate4) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    : predicate4.test(it) ? 3
                    :                       4,
                it -> it
        ).toImmutableList();
        val list1 = temp.filter(it -> it._1() == 0).map(it -> it._2());
        val list2 = temp.filter(it -> it._1() == 1).map(it -> it._2());
        val list3 = temp.filter(it -> it._1() == 2).map(it -> it._2());
        val list4 = temp.filter(it -> it._1() == 3).map(it -> it._2());
        val list5 = temp.filter(it -> it._1() == 4).map(it -> it._2());
        return Tuple.of(
                list1,
                list2,
                list3,
                list4,
                list5
        );
    }
    
    public default Tuple6, FuncList, FuncList, FuncList, FuncList, FuncList> split(
            Predicate predicate1,
            Predicate predicate2,
            Predicate predicate3,
            Predicate predicate4,
            Predicate predicate5) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    : predicate4.test(it) ? 3
                    : predicate5.test(it) ? 4
                    :                       5,
                it -> it
        ).toImmutableList();
        val list1 = temp.filter(it -> it._1() == 0).map(it -> it._2());
        val list2 = temp.filter(it -> it._1() == 1).map(it -> it._2());
        val list3 = temp.filter(it -> it._1() == 2).map(it -> it._2());
        val list4 = temp.filter(it -> it._1() == 3).map(it -> it._2());
        val list5 = temp.filter(it -> it._1() == 4).map(it -> it._2());
        val list6 = temp.filter(it -> it._1() == 5).map(it -> it._2());
        return Tuple.of(
                list1,
                list2,
                list3,
                list4,
                list5,
                list6
        );
    }
    
    //-- SplitToMap --
    
    public default  FuncMap> split(
            KEY key1, Predicate predicate,
            KEY key2) {
        val temp = this.mapTuple(
                it -> predicate.test(it) ? 0 : 1,
                it -> it
        ).toList();
        val list1 = (key1 != null) ? temp.filter(it -> it._1() == 0).map(it -> it._2()) : FuncList.empty();
        val list2 = (key2 != null) ? temp.filter(it -> it._1() == 1).map(it -> it._2()) : FuncList.empty();
        return FuncMap.of(
                key1, list1, 
                key2, list2);
    }
    
    public default  FuncMap> split(
            KEY key1, Predicate predicate1,
            KEY key2, Predicate predicate2,
            KEY key3) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    :                       2,
                it -> it
        ).toImmutableList();
        val list1 = (key1 != null) ? temp.filter(it -> it._1() == 0).map(it -> it._2()) : FuncList.empty();
        val list2 = (key2 != null) ? temp.filter(it -> it._1() == 1).map(it -> it._2()) : FuncList.empty();
        val list3 = (key3 != null) ? temp.filter(it -> it._1() == 2).map(it -> it._2()) : FuncList.empty();
        return FuncMap.of(
                key1, list1, 
                key2, list2, 
                key3, list3);
    }
    
    public default  FuncMap> split(
            KEY key1, Predicate predicate1,
            KEY key2, Predicate predicate2,
            KEY key3, Predicate predicate3,
            KEY key4) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    :                       3,
                it -> it
        ).toImmutableList();
        val list1 = (key1 != null) ? temp.filter(it -> it._1() == 0).map(it -> it._2()) : FuncList.empty();
        val list2 = (key2 != null) ? temp.filter(it -> it._1() == 1).map(it -> it._2()) : FuncList.empty();
        val list3 = (key3 != null) ? temp.filter(it -> it._1() == 2).map(it -> it._2()) : FuncList.empty();
        val list4 = (key4 != null) ? temp.filter(it -> it._1() == 3).map(it -> it._2()) : FuncList.empty();
        return FuncMap.of(
                key1, list1, 
                key2, list2, 
                key3, list3, 
                key4, list4);
    }
    
    public default  FuncMap> split(
            KEY key1, Predicate predicate1,
            KEY key2, Predicate predicate2,
            KEY key3, Predicate predicate3,
            KEY key4, Predicate predicate4,
            KEY key5) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    : predicate4.test(it) ? 3
                    :                       4,
                it -> it
        ).toImmutableList();
        val list1 = (key1 != null) ? temp.filter(it -> it._1() == 0).map(it -> it._2()) : FuncList.empty();
        val list2 = (key2 != null) ? temp.filter(it -> it._1() == 1).map(it -> it._2()) : FuncList.empty();
        val list3 = (key3 != null) ? temp.filter(it -> it._1() == 2).map(it -> it._2()) : FuncList.empty();
        val list4 = (key4 != null) ? temp.filter(it -> it._1() == 3).map(it -> it._2()) : FuncList.empty();
        val list5 = (key5 != null) ? temp.filter(it -> it._1() == 4).map(it -> it._2()) : FuncList.empty();
        return FuncMap.of(
                key1, list1, 
                key2, list2, 
                key3, list3, 
                key4, list4, 
                key5, list5);
    }
    
    public default  FuncMap> split(
            KEY key1, Predicate predicate1,
            KEY key2, Predicate predicate2,
            KEY key3, Predicate predicate3,
            KEY key4, Predicate predicate4,
            KEY key5, Predicate predicate5,
            KEY key6) {
        val temp = this.mapTuple(
                it -> predicate1.test(it) ? 0
                    : predicate2.test(it) ? 1
                    : predicate3.test(it) ? 2
                    : predicate4.test(it) ? 3
                    : predicate5.test(it) ? 4
                    :                       5,
                it -> it
        ).toImmutableList();
        val list1 = (key1 != null) ? temp.filter(it -> it._1() == 0).map(it -> it._2()) : FuncList.empty();
        val list2 = (key2 != null) ? temp.filter(it -> it._1() == 1).map(it -> it._2()) : FuncList.empty();
        val list3 = (key3 != null) ? temp.filter(it -> it._1() == 2).map(it -> it._2()) : FuncList.empty();
        val list4 = (key4 != null) ? temp.filter(it -> it._1() == 3).map(it -> it._2()) : FuncList.empty();
        val list5 = (key5 != null) ? temp.filter(it -> it._1() == 4).map(it -> it._2()) : FuncList.empty();
        val list6 = (key6 != null) ? temp.filter(it -> it._1() == 5).map(it -> it._2()) : FuncList.empty();
        return FuncMap.of(
                key1, list1, 
                key2, list2, 
                key3, list3, 
                key4, list4, 
                key5, list5,
                key6, list6);
    }
    
    //++ Plus w/ Self ++
    
    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();
        });
    }
    
    public default  T pipe(Function, T> piper) {
        return piper.apply(this);
    }
    
    public default Streamable collapse(Predicate conditionToCollapse, Func2 concatFunc) {
        return deriveWith(stream -> { 
            return StreamPlus.from(stream()).collapse(conditionToCollapse, concatFunc);
        });
    }
    
    public default  Streamable> spawn(Func1> mapper) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream()).spawn(mapper);
        });
    }
    
}