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

functionalj.list.FuncList 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.list;
   
import static functionalj.function.Func.alwaysTrue;
import static functionalj.lens.Access.$I;
import static java.util.function.Function.identity;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
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.stream.Collectors;
import java.util.stream.Stream;

import functionalj.function.Func1;
import functionalj.function.Func2;
import functionalj.pipeable.Pipeable;
import functionalj.promise.UncompletedAction;
import functionalj.result.Result;
import functionalj.stream.StreamPlus;
import functionalj.stream.StreamPlusHelper;
import functionalj.stream.Streamable;
import functionalj.tuple.IntTuple2;
import functionalj.tuple.Tuple;
import lombok.val;

@SuppressWarnings("javadoc")
public interface FuncList
        extends 
            ReadOnlyList, 
            Streamable, 
            Pipeable>, 
            Predicate,
            FuncListWithMapFirst,
            FuncListWithMapThen,
            FuncListWithMapTuple,
            FuncListWithMapToMap,
            FuncListWithFillNull,
            FuncListWithCombine,
            FuncListAdditionalOperations {
    
    public static  ImmutableList empty() {
        return ImmutableList.empty();
    }
    
    public static  ImmutableList emptyList() {
        return ImmutableList.empty();
    }
    
    public static  ImmutableList empty(Class elementClass) {
        return ImmutableList.empty();
    }
    
    public static  ImmutableList emptyList(Class elementClass) {
        return ImmutableList.empty();
    }
    
    @SafeVarargs
    public static  ImmutableList of(T... data) {
        return ImmutableList.of(data);
    }
    
    @SafeVarargs
    public static  ImmutableList AllOf(T... data) {
        return ImmutableList.of(data);
    }
    
    // TODO - Function to create FuncList from function of Array
    
    public static  ImmutableList from(T[] datas) {
        return ImmutableList.from(datas);
    }
    
    public static  ImmutableList from(Collection data) {
        return ImmutableList.from(data);
    }
    
    public static  ImmutableList from(List data) {
        return ImmutableList.from(data);
    }
    
    @SafeVarargs
    public static  ImmutableList ListOf(T... data) {
        return ImmutableList.of(data);
    }
    
    @SafeVarargs
    public static  ImmutableList listOf(T... data) {
        return ImmutableList.of(data);
    }
    
    public static  FuncList from(Streamable streamable) {
        return new FuncListDerived(streamable, identity());
    }
    
    public static  ImmutableList from(Stream stream) {
        return new ImmutableList(stream.collect(Collectors.toList()));
    }
    
    public static  ImmutableList from(ReadOnlyList readOnlyList) {
        return ImmutableList.from(readOnlyList);
    }
    
    public static  ImmutableList from(FuncList funcList) {
        return ImmutableList.from(funcList);
    }
    
    public static  FuncListBuilder newFuncList() {
        return new FuncListBuilder();
    }
    
    public static  FuncListBuilder newList() {
        return new FuncListBuilder();
    }
    
    public static  FuncListBuilder newBuilder() {
        return new FuncListBuilder();
    }
    
    // == Override ==
    
    @Override
    public default  FuncList deriveWith(Function, Stream> action) {
        val list = new FuncListDerived(this, action);
        val isLazy = isLazy();
        return isLazy ? list : new ImmutableList<>(list, false);
    }
    
    @Override
    public default  FuncList deriveFrom(Function, Stream> action) {
        return FuncListDerived.from((Supplier>) () -> {
            return action.apply(FuncList.this);
        });
    }
    
    @Override
    public default FuncList __data() throws Exception {
        return this;
    }
    
    @Override
    public default boolean test(DATA data) {
        return contains(data);
    }
    
    public default boolean isLazy() {
        return true;
    }
    
    public default boolean isEager() {
        return false;
    }
    
    public FuncList lazy();
    
    public FuncList eager();
    
    @Override
    public default List toJavaList() {
        return this;
    }
    
    public default FuncList toList() {
        return this;
    }
    
    public default ImmutableList freeze() {
        return toImmutableList();
    }
    
    // -- List specific --
    
    public default FuncList indexesOf(Predicate check) {
        return this.mapWithIndex((index, data) -> check.test(data) ? index : -1).filter($I.thatNotEqualsTo(-1))
                .toImmutableList();
    }
    
    @Override
    public default int indexOf(Object o) {
        return indexesOf(each -> Objects.equals(o, each)).findFirst().orElse(-1);
    }
    
    public default Optional first() {
        val valueRef = new AtomicReference();
        if (!StreamPlusHelper.hasAt(stream(), 0, valueRef))
            return Optional.empty();
    
        return Optional.ofNullable(valueRef.get());
    }
    
    public default FuncList first(int count) {
        val size  = size();
        val index = Math.max(0, size - count);
        return skip(index);
    }
    
    public default Optional last() {
        val size = this.size();
        if (size <= 0)
            return Optional.empty();
    
        return Optional.ofNullable(get(size - 1));
    }
    
    public default FuncList last(int count) {
        return limit(count);
    }
    
    public default Optional at(int index) {
        val ref = new AtomicReference();
        val found = StreamPlusHelper.hasAt(this.stream(), index, ref);
        if (!found)
            Optional.empty();
    
        return Optional.ofNullable(ref.get());
    }
    
    public default FuncList rest() {
        return deriveWith(stream -> stream.skip(1));
    }
    
    // Note - Eager
    public default FuncList reverse() {
        val temp = this.toMutableList();
        Collections.reverse(temp);
    
        val list = FuncList.from(temp);
        return isLazy() ? list.lazy() : list.eager();
    }
    
    // Note - Eager
    public default FuncList shuffle() {
        val temp = this.toMutableList();
        Collections.shuffle(temp);
    
        val list = FuncList.from(temp);
        return isLazy() ? list.lazy() : list.eager();
    }
    
    public default FuncList> query(Predicate check) {
        return this.mapWithIndex((index, data) -> check.test(data) ? new IntTuple2(index, data) : null)
                .filterNonNull();
    }
    
    public default > Optional minIndexBy(Func1 mapper) {
        return minIndexBy(alwaysTrue(), mapper);
    }
    
    public default > Optional maxIndexBy(Func1 mapper) {
        return maxIndexBy(alwaysTrue(), mapper);
    }
    
    public default > Optional minIndexBy(Predicate filter,
            Func1 mapper) {
        return stream().mapWithIndex(Tuple::of).filter(t -> filter.test(t._2)).minBy(t -> mapper.apply(t._2))
                .map(t -> t._1);
    }
    
    public default > Optional maxIndexBy(Predicate filter,
            Func1 mapper) {
        return stream().mapWithIndex(Tuple::of).filter(t -> filter.test(t._2)).maxBy(t -> mapper.apply(t._2))
                .map(t -> t._1);
    }
    
    // == Modified methods ==
    
    @Override
    public default Object[] toArray() {
        return stream().toArray();
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public default  T[] toArray(T[] a) {
        int count = size();
        if (a.length != count) {
            a = (T[])Array.newInstance(a.getClass().getComponentType(), count);
        }
        val array = a;
        forEachWithIndex((index, element) -> array[index] = (T)element);
        return array;
    }
    
    public default  A[] toArray(IntFunction generator) {
        return stream().toArray(generator);
    }
    
    public default FuncList append(DATA value) {
        return deriveWith(stream -> Stream.concat(stream, Stream.of(value)));
    }
    
    public default FuncList appendAll(DATA[] values) {
        return deriveWith(stream -> Stream.concat(stream, Stream.of(values)));
    }
    
    public default FuncList appendAll(Collection collection) {
        return ((collection == null) || collection.isEmpty()) ? this
                : deriveWith(stream -> Stream.concat(stream, collection.stream()));
    }
    
    public default FuncList appendAll(Supplier> supplier) {
        return (supplier == null) ? this : deriveWith(stream -> Stream.concat(stream, supplier.get()));
    }
    
    public default FuncList prepend(DATA value) {
        return deriveWith(stream -> Stream.concat(Stream.of(value), stream));
    }
    
    public default FuncList prependAll(DATA[] values) {
        return deriveWith(stream -> Stream.concat(Stream.of(values), stream));
    }
    
    public default FuncList prependAll(Collection collection) {
        return ((collection == null) || collection.isEmpty()) ? this
                : deriveWith(stream -> Stream.concat(collection.stream(), stream));
    }
    
    public default FuncList prependAll(Streamable streamable) {
        return (streamable == null) ? this : deriveWith(stream -> Stream.concat(streamable.stream(), stream));
    }
    
    public default FuncList prependAll(Supplier> supplier) {
        return (supplier == null) ? this : deriveWith(stream -> Stream.concat(supplier.get(), stream));
    }
    
    public default FuncList with(int index, DATA value) {
        if (index < 0)
            throw new IndexOutOfBoundsException(index + "");
        if (index >= size())
            throw new IndexOutOfBoundsException(index + " vs " + size());
    
        val i = new AtomicInteger();
        return deriveWith(stream -> stream.map(each -> (i.getAndIncrement() == index) ? value : each));
    }
    
    public default FuncList with(int index, Function mapper) {
        if (index < 0)
            throw new IndexOutOfBoundsException(index + "");
        if (index >= size())
            throw new IndexOutOfBoundsException(index + " vs " + size());
    
        val i = new AtomicInteger();
        return deriveWith(stream -> stream.map(each -> (i.getAndIncrement() == index) ? mapper.apply(each) : each));
    }
    
    @SuppressWarnings("unchecked")
    public default FuncList insertAt(int index, DATA... elements) {
        if ((elements == null) || (elements.length == 0))
            return this;
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return Stream.concat(streamable.stream().limit(index),
                    Stream.concat(Stream.of(elements), streamable.stream().skip(index + 1)));
        }));
    }
    
    public default FuncList insertAllAt(int index, Collection collection) {
        if ((collection == null) || collection.isEmpty())
            return this;
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return (Stream) Stream.concat(streamable.stream().limit(index),
                    Stream.concat(collection.stream(), streamable.stream().skip(index + 1)));
        }));
    }
    
    public default FuncList insertAllAt(int index, Streamable theStreamable) {
        if (theStreamable == null)
            return this;
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return Stream.concat(streamable.stream().limit(index),
                    Stream.concat(theStreamable.stream(), streamable.stream().skip(index + 1)));
        }));
    }
    
    public default FuncList excludeAt(int index) {
        if (index < 0)
            throw new IndexOutOfBoundsException("index: " + index);
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return Stream.concat(streamable.stream().limit(index), streamable.stream().skip(index + 2));
        }));
    }
    
    public default FuncList excludeFrom(int fromIndexInclusive, int count) {
        if (fromIndexInclusive < 0)
            throw new IndexOutOfBoundsException("fromIndexInclusive: " + fromIndexInclusive);
        if (count <= 0)
            throw new IndexOutOfBoundsException("count: " + count);
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return Stream.concat(stream().limit(fromIndexInclusive), stream().skip(fromIndexInclusive + count));
        }));
    }
    
    public default FuncList excludeBetween(int fromIndexInclusive, int toIndexExclusive) {
        if (fromIndexInclusive < 0)
            throw new IndexOutOfBoundsException("fromIndexInclusive: " + fromIndexInclusive);
        if (toIndexExclusive < 0)
            throw new IndexOutOfBoundsException("toIndexExclusive: " + toIndexExclusive);
        if (fromIndexInclusive > toIndexExclusive)
            throw new IndexOutOfBoundsException(
                    "fromIndexInclusive: " + fromIndexInclusive + ", toIndexExclusive: " + toIndexExclusive);
        if (fromIndexInclusive == toIndexExclusive)
            return this;
    
        return FuncListDerived.from(deriveFrom((Streamable streamable) -> {
            return Stream.concat(stream().limit(fromIndexInclusive), stream().skip(toIndexExclusive + 1));
        }));
    }
    
    @Override
    public default FuncList subList(int fromIndexInclusive, int toIndexExclusive) {
        val length = toIndexExclusive - fromIndexInclusive;
        return new FuncListDerived<>(this, stream -> stream.skip(fromIndexInclusive).limit(length));
    }
    
    // ============================================================================
    // NOTE: The following part of the code was copied from StreamPlus
    // We will write a program to do the copy and replace ...
    // in the mean time, change this in StreamPlus.
    // ++ Plus w/ Self ++
    
    @Override
    public default FuncList sequential() {
        return deriveWith(stream -> {
            return stream.sequential();
        });
    }
    
    @Override
    public default FuncList parallel() {
        return deriveWith(stream -> {
            return stream.parallel();
        });
    }
    
    @Override
    public default FuncList unordered() {
        return deriveWith(stream -> {
            return stream.unordered();
        });
    }
    
    public default  FuncList map(Function mapper) {
        return deriveWith(stream -> {
            return stream.map(mapper);
        });
    }
    
    public default  FuncList flatMap(
            Function> mapper) {
        return deriveWith(stream -> {
            return stream.flatMap(e -> mapper.apply(e).stream());
        });
    }
    
    public default FuncList filter(Predicate predicate) {
        return deriveWith(stream -> {
            return (predicate == null) ? stream : stream.filter(predicate);
        });
    }
   
    public default FuncList peek(Consumer action) {
        return deriveWith(stream -> {
            return (action == null) ? stream : stream.peek(action);
        });
    }
    
    // -- Limit/Skip --
    
    @Override
    public default FuncList limit(long maxSize) {
        return deriveWith(stream -> {
            return stream.limit(maxSize);
        });
    }
    
    @Override
    public default FuncList skip(long n) {
        return deriveWith(stream -> {
            return stream.skip(n);
        });
    }
    
    public default FuncList skipWhile(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).skipWhile(condition);
        });
    }
    
    public default FuncList skipUntil(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).skipUntil(condition);
        });
    }
    
    public default FuncList takeWhile(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).takeWhile(condition);
        });
    }
    
    public default FuncList takeUntil(Predicate condition) {
        return deriveWith(stream -> {
            return StreamPlus.from(stream).takeUntil(condition);
        });
    }
    
    @Override
    public default FuncList distinct() {
        return deriveWith(stream -> {
            return stream.distinct();
        });
    }
    
    @Override
    public default FuncList sorted() {
        return deriveWith(stream -> {
            return stream.sorted();
        });
    }
    
    @Override
    public default FuncList sorted(Comparator comparator) {
        return deriveWith(stream -> {
            return (comparator == null) ? stream.sorted() : stream.sorted(comparator);
        });
    }
    
    public default FuncList limit(Long maxSize) {
        return deriveWith(stream -> {
            return ((maxSize == null) || (maxSize.longValue() < 0)) ? stream : stream.limit(maxSize);
        });
    }
    
    public default FuncList skip(Long startAt) {
        return deriveWith(stream -> {
            return ((startAt == null) || (startAt.longValue() < 0)) ? stream : stream.skip(startAt);
        });
    }
    
    // -- Sorted --
    
    public default > FuncList 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  FuncList 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);
            });
        });
    }
    
    // -- accumulate --
    
    public default FuncList 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;
            }));
        });
    }
    
    // -- Filter --
    
    public default FuncList filterNonNull() {
        return deriveWith(stream -> stream.filter(Objects::nonNull));
    }
    
    public default FuncList exclude(DATA value) {
        return deriveWith(stream -> {
            return stream.filter(data -> !Objects.equals(value, data));
        });
    }
    
    public default FuncList excludeAll(DATA[] datas) {
        val dataList = FuncList.of(datas);
        return deriveWith(stream -> {
            return (datas == null) ? stream : stream.filter(data -> !dataList.contains(data));
        });
    }
    
    // TODO Join
    
    // -- Plus w/ Self --
    // ============================================================================
    
    public default FuncList 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);
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy