com.landawn.abacus.util.Seq Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abacus-util-all Show documentation
Show all versions of abacus-util-all Show documentation
A general programming library in Java
/*
* Copyright (c) 2017, Haiyang Li.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.landawn.abacus.util;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Random;
import java.util.RandomAccess;
import java.util.Set;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IndexedBiFunction;
import com.landawn.abacus.util.function.IndexedConsumer;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Predicate;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToBooleanFunction;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
import com.landawn.abacus.util.function.ToShortFunction;
import com.landawn.abacus.util.function.TriConsumer;
import com.landawn.abacus.util.function.TriFunction;
import com.landawn.abacus.util.stream.Collector;
import com.landawn.abacus.util.stream.Collectors;
/**
* It's an read-only wrapper for Collection
to support more daily used/functional methods.
* All the operations are null safety. And an empty String
/Array
/Collection
/Optional
/NullabLe
will be returned if possible, instead of null.
*
*
* Seq
should not be passed as a parameter or returned as a result because it's a pure utility class for the operations/calculation based on Collection/Array
*
* @since 0.8
*
* @author Haiyang Li
*/
public final class Seq extends ImmutableCollection {
/**
* The returned Seq
and the specified Collection
are backed by the same data.
* Any changes to one will appear in the other.
*
* @param c
*/
Seq(final Collection c) {
super(c);
}
public static Seq just(T t) {
return of(t);
}
@SafeVarargs
public static Seq of(final T... a) {
return of(Arrays.asList(a));
}
/**
* The returned Seq
and the specified Collection
are backed by the same data.
* Any changes to one will appear in the other.
*
* @param c
* @return
* @throws NullPointerException if the specified Collection
is null.
*/
public static Seq of(Collection c) {
return new Seq<>(c);
}
/**
*
* @param map
* @return
* @throws NullPointerException if the specified Map
is null.
*/
public static Seq> of(Map map) {
return of(map == null ? null : map.entrySet());
}
/**
* Returns the Collection
the Seq
is backed with recursively.
*
* @return
*/
public Collection interior() {
if (coll == null) {
return coll;
}
Collection tmp = coll;
if (tmp instanceof Seq) {
while (tmp instanceof Seq) {
tmp = ((Seq) tmp).coll;
}
}
if (tmp instanceof SubCollection) {
while (tmp instanceof SubCollection) {
tmp = ((SubCollection) tmp).c;
}
}
if (tmp instanceof Seq) {
return ((Seq) tmp).interior();
} else {
return tmp;
}
}
@Override
public boolean contains(Object e) {
if (N.isNullOrEmpty(coll)) {
return false;
}
return coll.contains(e);
}
@Override
public boolean containsAll(Collection> c) {
if (N.isNullOrEmpty(coll)) {
return false;
} else if (N.isNullOrEmpty(c)) {
return true;
}
return coll.containsAll(c);
}
public boolean containsAll(Object[] a) {
if (N.isNullOrEmpty(coll)) {
return false;
} else if (N.isNullOrEmpty(a)) {
return true;
}
return containsAll(Arrays.asList(a));
}
public boolean containsAny(Collection> c) {
if (N.isNullOrEmpty(coll) || N.isNullOrEmpty(c)) {
return false;
}
return !disjoint(c);
}
public boolean containsAny(Object[] a) {
if (N.isNullOrEmpty(coll) || N.isNullOrEmpty(a)) {
return false;
}
return !disjoint(a);
}
public boolean disjoint(final Collection> c) {
return Seq.disjoint(this.coll, c);
}
public boolean disjoint(final Object[] a) {
if (N.isNullOrEmpty(a)) {
return true;
}
return disjoint(Arrays.asList(a));
}
/**
*
* @param b
* @return
* @see IntList#intersection(IntList)
*/
public List intersection(Collection> b) {
if (N.isNullOrEmpty(coll) || N.isNullOrEmpty(b)) {
return new ArrayList<>();
}
final Multiset> bOccurrences = Multiset.from(b);
final List result = new ArrayList<>(N.min(9, size(), b.size()));
for (T e : coll) {
if (bOccurrences.getAndRemove(e) > 0) {
result.add(e);
}
}
return result;
}
public List intersection(final Object[] a) {
if (N.isNullOrEmpty(coll) || N.isNullOrEmpty(a)) {
return new ArrayList<>();
}
return intersection(Arrays.asList(a));
}
/**
*
* @param b
* @return
* @see IntList#difference(IntList)
*/
public List difference(Collection> b) {
if (N.isNullOrEmpty(coll)) {
return new ArrayList<>();
} else if (N.isNullOrEmpty(b)) {
return new ArrayList<>(coll);
}
final Multiset> bOccurrences = Multiset.from(b);
final List result = new ArrayList<>(N.min(size(), N.max(9, size() - b.size())));
for (T e : coll) {
if (bOccurrences.getAndRemove(e) < 1) {
result.add(e);
}
}
return result;
}
public List difference(final Object[] a) {
if (N.isNullOrEmpty(coll)) {
return new ArrayList<>();
} else if (N.isNullOrEmpty(a)) {
return new ArrayList<>(coll);
}
return difference(Arrays.asList(a));
}
/**
*
* @param b
* @return this.difference(b).addAll(b.difference(this))
* @see IntList#symmetricDifference(IntList)
*/
public List symmetricDifference(Collection b) {
if (N.isNullOrEmpty(b)) {
return N.isNullOrEmpty(coll) ? new ArrayList() : new ArrayList<>(coll);
} else if (N.isNullOrEmpty(coll)) {
return new ArrayList<>(b);
}
final Multiset> bOccurrences = Multiset.from(b);
final List result = new ArrayList<>(N.max(9, Math.abs(size() - b.size())));
for (T e : coll) {
if (bOccurrences.getAndRemove(e) < 1) {
result.add(e);
}
}
for (T e : b) {
if (bOccurrences.getAndRemove(e) > 0) {
result.add(e);
}
if (bOccurrences.isEmpty()) {
break;
}
}
return result;
}
public List symmetricDifference(final T[] a) {
if (N.isNullOrEmpty(a)) {
return N.isNullOrEmpty(coll) ? new ArrayList() : new ArrayList<>(coll);
} else if (N.isNullOrEmpty(coll)) {
return N.asList(a);
}
return symmetricDifference(Arrays.asList(a));
}
public int occurrencesOf(final Object objectToFind) {
return N.isNullOrEmpty(coll) ? 0 : N.occurrencesOf(coll, objectToFind);
}
@SuppressWarnings("rawtypes")
public NullabLe min() {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of((T) N.min((Collection) coll));
}
public NullabLe min(Comparator super T> cmp) {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of(N.min(coll, cmp));
}
@SuppressWarnings("rawtypes")
public NullabLe median() {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of((T) N.median((Collection) coll));
}
public NullabLe median(Comparator super T> cmp) {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of(N.median(coll, cmp));
}
@SuppressWarnings("rawtypes")
public NullabLe max() {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of((T) N.max((Collection) coll));
}
public NullabLe max(Comparator super T> cmp) {
return size() == 0 ? (NullabLe) NullabLe.empty() : NullabLe.of(N.max(coll, cmp));
}
@SuppressWarnings("rawtypes")
public NullabLe kthLargest(final int k) {
return size() < k ? (NullabLe) NullabLe.empty() : NullabLe.of((T) N.kthLargest((Collection) coll, k));
}
public NullabLe kthLargest(final int k, Comparator super T> cmp) {
return size() < k ? (NullabLe) NullabLe.empty() : NullabLe.of(N.kthLargest(coll, k, cmp));
}
public int sumInt() {
if (N.isNullOrEmpty(coll)) {
return 0;
}
int result = 0;
for (T e : coll) {
if (e != null) {
result += ((Number) e).intValue();
}
}
return result;
}
public int sumInt(final ToIntFunction super T> mapper) {
if (N.isNullOrEmpty(coll)) {
return 0;
}
int result = 0;
for (T e : coll) {
result += mapper.applyAsInt(e);
}
return result;
}
public long sumLong() {
if (N.isNullOrEmpty(coll)) {
return 0L;
}
long result = 0;
for (T e : coll) {
if (e != null) {
result += ((Number) e).longValue();
}
}
return result;
}
public long sumLong(final ToLongFunction super T> mapper) {
if (N.isNullOrEmpty(coll)) {
return 0L;
}
long result = 0L;
for (T e : coll) {
result += mapper.applyAsLong(e);
}
return result;
}
public double sumDouble() {
if (N.isNullOrEmpty(coll)) {
return 0D;
}
return sumDouble((ToDoubleFunction super T>) new ToDoubleFunction() {
@Override
public double applyAsDouble(Number value) {
return value == null ? 0d : value.doubleValue();
}
});
}
public double sumDouble(final ToDoubleFunction super T> mapper) {
return size() == 0 ? 0d : N.sumDouble(coll, mapper);
}
public OptionalDouble averageInt() {
return size() == 0 ? OptionalDouble.empty() : OptionalDouble.of(((double) sumInt()) / size());
}
public OptionalDouble averageInt(final ToIntFunction super T> mapper) {
return size() == 0 ? OptionalDouble.empty() : OptionalDouble.of(((double) sumInt(mapper)) / size());
}
public OptionalDouble averageLong() {
return size() == 0 ? OptionalDouble.empty() : OptionalDouble.of(((double) sumLong()) / size());
}
public OptionalDouble averageLong(final ToLongFunction super T> mapper) {
return size() == 0 ? OptionalDouble.empty() : OptionalDouble.of(((double) sumLong(mapper)) / size());
}
public OptionalDouble averageDouble() {
return averageDouble((ToDoubleFunction super T>) new ToDoubleFunction() {
@Override
public double applyAsDouble(Number value) {
return value == null ? 0d : value.doubleValue();
}
});
}
public OptionalDouble averageDouble(final ToDoubleFunction super T> mapper) {
return size() == 0 ? OptionalDouble.empty() : N.averageDouble(coll, mapper);
}
public void forEach(final Consumer super T> action) {
N.forEach(coll, action);
}
// public void forEach(int fromIndex, final int toIndex, final Consumer super T> action) {
// N.forEach(coll, fromIndex, toIndex, action);
// }
public void forEach(final IndexedConsumer super T> action) {
N.forEach(coll, action);
}
// public void forEach(int fromIndex, final int toIndex, final IndexedConsumer super T> action) {
// N.forEach(coll, fromIndex, toIndex, action);
// }
public R forEach(final R seed, BiFunction accumulator, final BiPredicate super R, ? super T> conditionToBreak) {
return N.forEach(coll, seed, accumulator, conditionToBreak);
}
// public R forEach(int fromIndex, final int toIndex, final R seed, final BiFunction accumulator,
// final BiPredicate super R, ? super T> conditionToBreak) {
// return N.forEach(coll, fromIndex, toIndex, seed, accumulator, conditionToBreak);
// }
/**
* Execute accumulator
on each element till true
is returned by conditionToBreak
*
* @param seed The seed element is both the initial value of the reduction and the default result if there are no elements.
* @param accumulator
* @param conditionToBreak break if true
is return.
* @return
*/
public R forEach(final R seed, final IndexedBiFunction accumulator, final BiPredicate super R, ? super T> conditionToBreak) {
return N.forEach(coll, seed, accumulator, conditionToBreak);
}
public void forEach(final Function super T, ? extends Collection> mapper, final BiConsumer super T, ? super U> action) {
if (N.isNullOrEmpty(coll)) {
return;
}
for (T e : coll) {
final Collection c = mapper.apply(e);
if (N.notNullOrEmpty(c)) {
for (U u : c) {
action.accept(e, u);
}
}
}
}
public void forEach(final Function super T, ? extends Collection> mapper2, final Function super T2, ? extends Collection> mapper3,
final TriConsumer super T, ? super T2, ? super T3> action) {
if (N.isNullOrEmpty(coll)) {
return;
}
for (T e : coll) {
final Collection c2 = mapper2.apply(e);
if (N.notNullOrEmpty(c2)) {
for (T2 t2 : c2) {
final Collection c3 = mapper3.apply(t2);
if (N.notNullOrEmpty(c3)) {
for (T3 t3 : c3) {
action.accept(e, t2, t3);
}
}
}
}
}
}
public void forEachPair(final BiConsumer super T, ? super T> action) {
forEachPair(action, 1);
}
public void forEachPair(final BiConsumer super T, ? super T> action, final int increment) {
final int windowSize = 2;
N.checkArgument(windowSize > 0 && increment > 0, "'windowSize'=%s and 'increment'=%s must not be less than 1", windowSize, increment);
if (N.isNullOrEmpty(coll)) {
return;
}
final Iterator iter = coll.iterator();
final T NONE = (T) N.NULL_MASK;
T prev = NONE;
while (iter.hasNext()) {
if (increment > windowSize && prev != NONE) {
int skipNum = increment - windowSize;
while (skipNum-- > 0 && iter.hasNext()) {
iter.next();
}
if (iter.hasNext() == false) {
break;
}
prev = NONE;
}
if (increment == 1) {
action.accept(prev == NONE ? iter.next() : prev, (prev = (iter.hasNext() ? iter.next() : null)));
} else {
action.accept(iter.next(), (prev = (iter.hasNext() ? iter.next() : null)));
}
}
}
public void forEachTriple(final TriConsumer super T, ? super T, ? super T> action) {
forEachTriple(action, 1);
}
public void forEachTriple(final TriConsumer super T, ? super T, ? super T> action, final int increment) {
final int windowSize = 3;
N.checkArgument(windowSize > 0 && increment > 0, "'windowSize'=%s and 'increment'=%s must not be less than 1", windowSize, increment);
if (N.isNullOrEmpty(coll)) {
return;
}
final Iterator iter = coll.iterator();
final T NONE = (T) N.NULL_MASK;
T prev = NONE;
T prev2 = NONE;
while (iter.hasNext()) {
if (increment > windowSize && prev != NONE) {
int skipNum = increment - windowSize;
while (skipNum-- > 0 && iter.hasNext()) {
iter.next();
}
if (iter.hasNext() == false) {
break;
}
prev = NONE;
}
if (increment == 1) {
action.accept(prev2 == NONE ? iter.next() : prev2, (prev2 = (prev == NONE ? (iter.hasNext() ? iter.next() : null) : prev)),
(prev = (iter.hasNext() ? iter.next() : null)));
} else if (increment == 2) {
action.accept(prev == NONE ? iter.next() : prev, (prev2 = (iter.hasNext() ? iter.next() : null)),
(prev = (iter.hasNext() ? iter.next() : null)));
} else {
action.accept(iter.next(), (prev2 = (iter.hasNext() ? iter.next() : null)), (prev = (iter.hasNext() ? iter.next() : null)));
}
}
}
// /**
// * Execute accumulator
on each element till true
is returned by conditionToBreak
// *
// * @param fromIndex
// * @param toIndex
// * @param seed The seed element is both the initial value of the reduction and the default result if there are no elements.
// * @param accumulator
// * @param conditionToBreak break if true
is return.
// * @return
// */
// public R forEach(int fromIndex, final int toIndex, final R seed, final IndexedBiFunction accumulator,
// final BiPredicate super R, ? super T> conditionToBreak) {
// return N.forEach(coll, fromIndex, toIndex, seed, accumulator, conditionToBreak);
// }
public NullabLe first() {
if (size() == 0) {
return NullabLe.empty();
}
if (coll instanceof List && coll instanceof RandomAccess) {
return NullabLe.of(((List) coll).get(0));
} else {
return NullabLe.of(coll.iterator().next());
}
}
/**
* Return at most first n
elements.
*
* @param n
* @return
*/
public List first(final int n) {
N.checkArgument(n >= 0, "'n' can't be negative: " + n);
if (N.isNullOrEmpty(coll) || n == 0) {
return new ArrayList<>();
} else if (coll.size() <= n) {
return new ArrayList<>(coll);
} else if (coll instanceof List) {
return new ArrayList<>(((List) coll).subList(0, n));
} else {
return new ArrayList<>(slice(0, n));
}
}
public NullabLe last() {
if (size() == 0) {
return NullabLe.empty();
}
if (coll instanceof List && coll instanceof RandomAccess) {
return NullabLe.of(((List) coll).get(size() - 1));
} else {
final Iterator iter = iterator();
T e = null;
while (iter.hasNext()) {
e = iter.next();
}
return NullabLe.of(e);
}
}
/**
* Return at most last n
elements.
*
* @param n
* @return
*/
public List last(final int n) {
N.checkArgument(n >= 0, "'n' can't be negative: " + n);
if (N.isNullOrEmpty(coll) || n == 0) {
return new ArrayList<>();
} else if (coll.size() <= n) {
return new ArrayList<>(coll);
} else if (coll instanceof List) {
return new ArrayList<>(((List) coll).subList(coll.size() - n, coll.size()));
} else {
return new ArrayList<>(slice(coll.size() - n, coll.size()));
}
}
public NullabLe findFirst(Predicate super T> predicate) {
if (size() == 0) {
return NullabLe.empty();
}
for (T e : coll) {
if (predicate.test(e)) {
return NullabLe.of(e);
}
}
return NullabLe.empty();
}
public NullabLe findLast(Predicate super T> predicate) {
if (size() == 0) {
return NullabLe.empty();
}
if (coll instanceof List) {
final List list = (List) coll;
if (coll instanceof RandomAccess) {
for (int i = size() - 1; i >= 0; i--) {
if (predicate.test(list.get(i))) {
return NullabLe.of(list.get(i));
}
}
} else {
final ListIterator iter = list.listIterator(list.size());
T pre = null;
while (iter.hasPrevious()) {
if (predicate.test((pre = iter.previous()))) {
return NullabLe.of(pre);
}
}
}
return NullabLe.empty();
} else {
T result = (T) N.NULL_MASK;
for (T e : coll) {
if (predicate.test(e)) {
result = e;
}
}
return result == N.NULL_MASK ? (NullabLe) NullabLe.empty() : NullabLe.of(result);
}
}
public OptionalInt findFirstIndex(Predicate super T> predicate) {
if (size() == 0) {
return OptionalInt.empty();
}
int idx = 0;
for (T e : coll) {
if (predicate.test(e)) {
return OptionalInt.of(idx);
}
idx++;
}
return OptionalInt.empty();
}
public OptionalInt findLastIndex(Predicate super T> predicate) {
if (size() == 0) {
return OptionalInt.empty();
}
if (coll instanceof List) {
final List list = (List) coll;
if (coll instanceof RandomAccess) {
for (int i = size() - 1; i >= 0; i--) {
if (predicate.test(list.get(i))) {
return OptionalInt.of(i);
}
}
} else {
final ListIterator iter = list.listIterator(list.size());
for (int i = size() - 1; iter.hasPrevious(); i--) {
if (predicate.test(iter.previous())) {
return OptionalInt.of(i);
}
}
}
return OptionalInt.empty();
} else {
int result = -1;
int idx = 0;
for (T e : coll) {
if (predicate.test(e)) {
result = idx;
}
idx++;
}
return result == -1 ? OptionalInt.empty() : OptionalInt.of(result);
}
}
public NullabLe findFirstOrLast(final Predicate super T> predicateForFirst, final Predicate super T> predicateForLast) {
if (N.isNullOrEmpty(coll)) {
return NullabLe. empty();
}
final Iterator iter = iterator();
T last = (T) N.NULL_MASK;
T next = null;
while (iter.hasNext()) {
next = iter.next();
if (predicateForFirst.test(next)) {
return NullabLe.of(next);
} else if (predicateForLast.test(next)) {
last = next;
}
}
return last == N.NULL_MASK ? NullabLe. empty() : NullabLe.of(last);
}
public OptionalInt findFirstOrLastIndex(final Predicate super T> predicateForFirst, final Predicate super T> predicateForLast) {
if (N.isNullOrEmpty(coll)) {
return OptionalInt.empty();
}
final Iterator iter = iterator();
T next = null;
int idx = 0, lastIndex = -1;
while (iter.hasNext()) {
next = iter.next();
if (predicateForFirst.test(next)) {
return OptionalInt.of(idx);
} else if (predicateForLast.test(next)) {
lastIndex = idx;
}
idx++;
}
return lastIndex == -1 ? OptionalInt.empty() : OptionalInt.of(lastIndex);
}
public Pair, NullabLe> findFirstAndLast(final Predicate super T> predicate) {
return findFirstAndLast(predicate, predicate);
}
public Pair, NullabLe> findFirstAndLast(final Predicate super T> predicateForFirst, final Predicate super T> predicateForLast) {
if (N.isNullOrEmpty(coll)) {
return Pair.of(NullabLe. empty(), NullabLe. empty());
}
return Pair.of(findFirst(predicateForFirst), findLast(predicateForLast));
}
public Pair findFirstAndLastIndex(final Predicate super T> predicate) {
return findFirstAndLastIndex(predicate, predicate);
}
public Pair findFirstAndLastIndex(final Predicate super T> predicateForFirst, final Predicate super T> predicateForLast) {
if (N.isNullOrEmpty(coll)) {
return Pair.of(OptionalInt.empty(), OptionalInt.empty());
}
return Pair.of(findFirstIndex(predicateForFirst), findLastIndex(predicateForLast));
}
public boolean allMatch(Predicate super T> filter) {
if (N.isNullOrEmpty(coll)) {
return true;
}
for (T e : coll) {
if (filter.test(e) == false) {
return false;
}
}
return true;
}
public boolean anyMatch(Predicate super T> filter) {
if (N.isNullOrEmpty(coll)) {
return false;
}
for (T e : coll) {
if (filter.test(e)) {
return true;
}
}
return false;
}
public boolean noneMatch(Predicate super T> filter) {
if (N.isNullOrEmpty(coll)) {
return true;
}
for (T e : coll) {
if (filter.test(e)) {
return false;
}
}
return true;
}
public boolean hasDuplicates() {
return N.hasDuplicates(coll, false);
}
public int count(Predicate super T> filter) {
return N.count(coll, filter);
}
public List filter(Predicate super T> filter) {
return N.filter(coll, filter);
}
public List filter(Predicate super T> filter, final int max) {
return N.filter(coll, filter, max);
}
public List filter(final U seed, final BiPredicate super T, ? super U> predicate) {
return filter(new Predicate() {
@Override
public boolean test(T value) {
return predicate.test(value, seed);
}
});
}
// public List filterThenMap(Predicate super T> filter, final Function super T, ? extends R> mapper) {
// if (N.isNullOrEmpty(coll)) {
// return new ArrayList<>();
// }
//
// final List res = new ArrayList<>();
//
// for (T e : coll) {
// if (filter.test(e)) {
// res.add(mapper.apply(e));
// }
// }
//
// return res;
// }
//
// public List filterThenFlatMap(Predicate super T> filter, final Function super T, ? extends Collection> mapper) {
// if (N.isNullOrEmpty(coll)) {
// return new ArrayList<>();
// }
//
// final List res = new ArrayList<>();
//
// for (T e : coll) {
// if (filter.test(e)) {
// res.addAll(mapper.apply(e));
// }
// }
//
// return res;
// }
//
// public List filterThenFlatMap2(Predicate super T> filter, final Function super T, ? extends R[]> mapper) {
// if (N.isNullOrEmpty(coll)) {
// return new ArrayList<>();
// }
//
// final List res = new ArrayList<>();
// R[] a = null;
//
// for (T e : coll) {
// if (filter.test(e)) {
// a = mapper.apply(e);
//
// if (N.notNullOrEmpty(a)) {
// if (a.length < 9) {
// for (R r : a) {
// res.add(r);
// }
// } else {
// res.addAll(Arrays.asList(a));
// }
// }
// }
// }
//
// return res;
// }
//
// public NullabLe filterThenReduce(Predicate super T> filter, final BinaryOperator accumulator) {
// if (N.isNullOrEmpty(coll)) {
// return NullabLe. empty();
// }
//
// T result = (T) N.NULL_MASK;
//
// for (T e : coll) {
// if (filter.test(e)) {
// result = result == N.NULL_MASK ? e : accumulator.apply(result, e);
// }
// }
//
// return result == N.NULL_MASK ? NullabLe. empty() : NullabLe.of(result);
// }
//
// public NullabLe filterThenReduce(Predicate super T> filter, final U identity, final BiFunction accumulator) {
// if (N.isNullOrEmpty(coll)) {
// return NullabLe.of(identity);
// }
//
// U result = identity;
//
// for (T e : coll) {
// if (filter.test(e)) {
// result = accumulator.apply(result, e);
// }
// }
//
// return NullabLe.of(result);
// }
//
// public R filterThenCollect(Predicate super T> filter, final Supplier supplier, final BiConsumer accumulator) {
// final R result = supplier.get();
//
// if (N.notNullOrEmpty(coll)) {
// for (T e : coll) {
// if (filter.test(e)) {
// accumulator.accept(result, e);
// }
// }
// }
//
// return result;
// }
//
// public R filterThenCollect(Predicate super T> filter, final Collector super T, A, R> collector) {
// final BiConsumer accumulator = collector.accumulator();
// final A result = collector.supplier().get();
//
// if (N.notNullOrEmpty(coll)) {
// for (T e : coll) {
// if (filter.test(e)) {
// accumulator.accept(result, e);
// }
// }
// }
//
// return collector.finisher().apply(result);
// }
public List takeWhile(Predicate super T> filter) {
final List result = new ArrayList<>(N.min(9, size()));
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
if (filter.test(e)) {
result.add(e);
} else {
break;
}
}
return result;
}
public List takeWhile(final U seed, final BiPredicate super T, ? super U> predicate) {
return takeWhile(new Predicate() {
@Override
public boolean test(T value) {
return predicate.test(value, seed);
}
});
}
public List takeWhileInclusive(Predicate super T> filter) {
final List result = new ArrayList<>(N.min(9, size()));
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.add(e);
if (filter.test(e) == false) {
break;
}
}
return result;
}
public List takeWhileInclusive(final U seed, final BiPredicate super T, ? super U> predicate) {
return takeWhileInclusive(new Predicate() {
@Override
public boolean test(T value) {
return predicate.test(value, seed);
}
});
}
public List dropWhile(Predicate super T> filter) {
final List result = new ArrayList<>(N.min(9, size()));
if (N.isNullOrEmpty(coll)) {
return result;
}
final Iterator iter = iterator();
T e = null;
while (iter.hasNext()) {
e = iter.next();
if (filter.test(e) == false) {
result.add(e);
break;
}
}
while (iter.hasNext()) {
result.add(iter.next());
}
return result;
}
public List dropWhile(final U seed, final BiPredicate super T, ? super U> predicate) {
return dropWhile(new Predicate() {
@Override
public boolean test(T value) {
return predicate.test(value, seed);
}
});
}
public List skipUntil(final Predicate super T> filter) {
return dropWhile(new Predicate() {
@Override
public boolean test(T value) {
return !filter.test(value);
}
});
}
public List skipUntil(final U seed, final BiPredicate super T, ? super U> predicate) {
return dropWhile(new Predicate() {
@Override
public boolean test(T value) {
return !predicate.test(value, seed);
}
});
}
public List map(final Function super T, ? extends R> func) {
return N.map(coll, func);
}
public BooleanList mapToBoolean(final ToBooleanFunction super T> func) {
return N.mapToBoolean(coll, func);
}
public CharList mapToChar(final ToCharFunction super T> func) {
return N.mapToChar(coll, func);
}
public ByteList mapToByte(final ToByteFunction super T> func) {
return N.mapToByte(coll, func);
}
public ShortList mapToShort(final ToShortFunction super T> func) {
return N.mapToShort(coll, func);
}
public IntList mapToInt(final ToIntFunction super T> func) {
return N.mapToInt(coll, func);
}
public LongList mapToLong(final ToLongFunction super T> func) {
return N.mapToLong(coll, func);
}
public FloatList mapToFloat(final ToFloatFunction super T> func) {
return N.mapToFloat(coll, func);
}
public DoubleList mapToDouble(final ToDoubleFunction super T> func) {
return N.mapToDouble(coll, func);
}
public List flatMap(final Function super T, ? extends Collection> func) {
final List result = new ArrayList<>(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public List flatMap2(final Function super T, ? extends R[]> func) {
final List result = new ArrayList<>(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
R[] a = null;
for (T e : coll) {
a = func.apply(e);
if (N.notNullOrEmpty(a)) {
if (a.length < 9) {
for (R r : a) {
result.add(r);
}
} else {
result.addAll(Arrays.asList(a));
}
}
}
return result;
}
public BooleanList flatMapToBoolean(final Function super T, ? extends Collection> func) {
final BooleanList result = new BooleanList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (boolean b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public BooleanList flatMapToBoolean2(final Function super T, boolean[]> func) {
final BooleanList result = new BooleanList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public CharList flatMapToChar(final Function super T, ? extends Collection> func) {
final CharList result = new CharList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (char b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public CharList flatMapToChar2(final Function super T, char[]> func) {
final CharList result = new CharList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public ByteList flatMapToByte(final Function super T, ? extends Collection> func) {
final ByteList result = new ByteList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (byte b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public ByteList flatMapToByte2(final Function super T, byte[]> func) {
final ByteList result = new ByteList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public ShortList flatMapToShort(final Function super T, ? extends Collection> func) {
final ShortList result = new ShortList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (short b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public ShortList flatMapToShort2(final Function super T, short[]> func) {
final ShortList result = new ShortList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public IntList flatMapToInt(final Function super T, ? extends Collection> func) {
final IntList result = new IntList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (int b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public IntList flatMapToInt2(final Function super T, int[]> func) {
final IntList result = new IntList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public LongList flatMapToLong(final Function super T, ? extends Collection> func) {
final LongList result = new LongList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (long b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public LongList flatMapToLong2(final Function super T, long[]> func) {
final LongList result = new LongList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public FloatList flatMapToFloat(final Function super T, ? extends Collection> func) {
final FloatList result = new FloatList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (float b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public FloatList flatMapToFloat2(final Function super T, float[]> func) {
final FloatList result = new FloatList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public DoubleList flatMapToDouble(final Function super T, ? extends Collection> func) {
final DoubleList result = new DoubleList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
for (double b : func.apply(e)) {
result.add(b);
}
}
return result;
}
public DoubleList flatMapToDouble2(final Function super T, double[]> func) {
final DoubleList result = new DoubleList(size() > N.MAX_ARRAY_SIZE / 2 ? N.MAX_ARRAY_SIZE : size() * 2);
if (N.isNullOrEmpty(coll)) {
return result;
}
for (T e : coll) {
result.addAll(func.apply(e));
}
return result;
}
public List flatMap(final Function super T, ? extends Collection> mapper, final BiFunction super T, ? super U, ? extends R> func) {
if (N.isNullOrEmpty(coll)) {
return new ArrayList();
}
final List result = new ArrayList(N.max(9, coll.size()));
for (T e : coll) {
final Collection c = mapper.apply(e);
if (N.notNullOrEmpty(c)) {
for (U u : c) {
result.add(func.apply(e, u));
}
}
}
return result;
}
public List flatMap(final Function super T, ? extends Collection> mapper2,
final Function super T2, ? extends Collection> mapper3, final TriFunction super T, ? super T2, ? super T3, R> func) {
if (N.isNullOrEmpty(coll)) {
return new ArrayList();
}
final List result = new ArrayList(N.max(9, coll.size()));
for (T e : coll) {
final Collection c2 = mapper2.apply(e);
if (N.notNullOrEmpty(c2)) {
for (T2 t2 : c2) {
final Collection c3 = mapper3.apply(t2);
if (N.notNullOrEmpty(c3)) {
for (T3 t3 : c3) {
result.add(func.apply(e, t2, t3));
}
}
}
}
}
return result;
}
/**
* Merge series of adjacent elements which satisfy the given predicate using
* the merger function and return a new stream.
*
*
* This method only run sequentially, even in parallel stream.
*
* @param collapsible
* @param mergeFunction
* @return
*/
public List collapse(final BiPredicate super T, ? super T> collapsible, final BiFunction super T, ? super T, T> mergeFunction) {
final List result = new ArrayList<>();
if (N.isNullOrEmpty(coll)) {
return result;
}
final Iterator iter = iterator();
boolean hasNext = false;
T next = null;
while (hasNext || iter.hasNext()) {
T res = hasNext ? next : (next = iter.next());
while ((hasNext = iter.hasNext())) {
if (collapsible.test(next, (next = iter.next()))) {
res = mergeFunction.apply(res, next);
} else {
break;
}
}
result.add(res);
}
return result;
}
/**
* Merge series of adjacent elements which satisfy the given predicate using
* the merger function and return a new stream.
*
*
* This method only run sequentially, even in parallel stream.
*
* @param collapsible
* @param collector
* @return
*/
public List collapse(final BiPredicate super T, ? super T> collapsible, final Collector super T, A, R> collector) {
final List result = new ArrayList<>();
if (N.isNullOrEmpty(coll)) {
return result;
}
final Supplier supplier = collector.supplier();
final BiConsumer accumulator = collector.accumulator();
final Function finisher = collector.finisher();
final Iterator iter = iterator();
boolean hasNext = false;
T next = null;
while (hasNext || iter.hasNext()) {
final A c = supplier.get();
accumulator.accept(c, hasNext ? next : (next = iter.next()));
while ((hasNext = iter.hasNext())) {
if (collapsible.test(next, (next = iter.next()))) {
accumulator.accept(c, next);
} else {
break;
}
}
result.add(finisher.apply(c));
}
return result;
}
/**
* Returns a {@code Stream} produced by iterative application of a accumulation function
* to an initial element {@code identity} and next element of the current stream.
* Produces a {@code Stream} consisting of {@code identity}, {@code acc(identity, value1)},
* {@code acc(acc(identity, value1), value2)}, etc.
*
* This is an intermediate operation.
*
*
Example:
*
* accumulator: (a, b) -> a + b
* stream: [1, 2, 3, 4, 5]
* result: [1, 3, 6, 10, 15]
*
*
*
* This method only run sequentially, even in parallel stream.
*
* @param accumulator the accumulation function
* @return the new stream which has the extract same size as this stream.
*/
public List scan(final BiFunction super T, ? super T, T> accumulator) {
final List result = new ArrayList<>();
if (N.isNullOrEmpty(coll)) {
return result;
}
final Iterator iter = iterator();
T next = null;
if (iter.hasNext()) {
result.add((next = iter.next()));
}
while (iter.hasNext()) {
result.add((next = accumulator.apply(next, iter.next())));
}
return result;
}
/**
* Returns a {@code Stream} produced by iterative application of a accumulation function
* to an initial element {@code identity} and next element of the current stream.
* Produces a {@code Stream} consisting of {@code identity}, {@code acc(identity, value1)},
* {@code acc(acc(identity, value1), value2)}, etc.
*
* This is an intermediate operation.
*
*
Example:
*
* seed:10
* accumulator: (a, b) -> a + b
* stream: [1, 2, 3, 4, 5]
* result: [11, 13, 16, 20, 25]
*
*
*
* This method only run sequentially, even in parallel stream.
*
* @param seed the initial value. it's only used once by accumulator
to calculate the fist element in the returned stream.
* It will be ignored if this stream is empty and won't be the first element of the returned stream.
*
* @param accumulator the accumulation function
* @return the new stream which has the extract same size as this stream.
*/
public List scan(final R seed, final BiFunction super R, ? super T, R> accumulator) {
final List result = new ArrayList<>();
if (N.isNullOrEmpty(coll)) {
return result;
}
final Iterator iter = iterator();
R next = seed;
while (iter.hasNext()) {
result.add((next = accumulator.apply(next, iter.next())));
}
return result;
}
/**
* This is equivalent to:
*
*
* if (isEmpty()) {
* return NullabLe.empty();
* }
*
* final Iterator iter = iterator();
* T result = iter.next();
*
* while (iter.hasNext()) {
* result = accumulator.apply(result, iter.next());
* }
*
* return NullabLe.of(result);
*
*
*
* @param accumulator
* @return
*/
public NullabLe reduce(BinaryOperator accumulator) {
if (isEmpty()) {
return NullabLe.empty();
}
final Iterator iter = iterator();
T result = iter.next();
while (iter.hasNext()) {
result = accumulator.apply(result, iter.next());
}
return NullabLe.of(result);
}
/**
* This is equivalent to:
*
*
* if (isEmpty()) {
* return identity;
* }
*
* final Iterator iter = iterator();
* U result = identity;
*
* while (iter.hasNext()) {
* result = accumulator.apply(result, iter.next());
* }
*
* return result;
*
*
*
* @param identity
* @param accumulator
* @return
*/
public U reduce(U identity, BiFunction accumulator) {
if (isEmpty()) {
return identity;
}
final Iterator iter = iterator();
U result = identity;
while (iter.hasNext()) {
result = accumulator.apply(result, iter.next());
}
return result;
}
public R collect(final Supplier supplier, final BiConsumer accumulator) {
final R result = supplier.get();
if (N.notNullOrEmpty(coll)) {
for (T e : coll) {
accumulator.accept(result, e);
}
}
return result;
}
public R collect(final Collector super T, A, R> collector) {
final BiConsumer accumulator = collector.accumulator();
final A result = collector.supplier().get();
if (N.notNullOrEmpty(coll)) {
for (T e : coll) {
accumulator.accept(result, e);
}
}
return collector.finisher().apply(result);
}
public RR collectAndThen(final Collector downstream, final Function finisher) {
return finisher.apply(collect(downstream));
}
@SafeVarargs
public final List append(T... a) {
return append(Arrays.asList(a));
}
public List append(final Collection extends T> c) {
return Seq.concat(this, c);
}
@SafeVarargs
public final List prepend(T... a) {
return prepend(Arrays.asList(a));
}
public List prepend(final Collection extends T> c) {
return Seq.concat(c, this);
}
public List merge(final Collection extends T> b, final BiFunction super T, ? super T, Nth> nextSelector) {
return Seq.merge(this, b, nextSelector);
}
public List zipWith(final Collection b, final BiFunction super T, ? super B, R> zipFunction) {
return Seq.zip(this, b, zipFunction);
}
public List zipWith(final Collection b, final T valueForNoneA, final B valueForNoneB, final BiFunction super T, ? super B, R> zipFunction) {
return Seq.zip(this, b, valueForNoneA, valueForNoneB, zipFunction);
}
public List zipWith(final Collection b, final Collection c, final TriFunction super T, ? super B, ? super C, R> zipFunction) {
return Seq.zip(this, b, c, zipFunction);
}
public List zipWith(final Collection b, final Collection c, final T valueForNoneA, final B valueForNoneB, final C valueForNoneC,
final TriFunction super T, ? super B, ? super C, R> zipFunction) {
return Seq.zip(this, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction);
}
public List intersperse(T value) {
if (isEmpty()) {
return new ArrayList<>();
}
final int size = size();
final List result = new ArrayList<>(size * 2 - 1);
int idx = 0;
for (T e : coll) {
result.add(e);
if (++idx < size) {
result.add(value);
}
}
return result;
}
public List> indexed() {
final List> result = new ArrayList<>(size());
if (N.isNullOrEmpty(coll)) {
return result;
}
int idx = 0;
for (T e : coll) {
result.add(Indexed.of(e, idx++));
}
return result;
}
/**
*
* @return a new List with distinct elements
*/
public List distinct() {
return N.distinct(coll);
}
/**
*
* @param keyExtractor don't change value of the input parameter.
* @return
*/
public List distinctBy(final Function super T, ?> keyExtractor) {
return N.distinctBy(coll, keyExtractor);
}
@SuppressWarnings("rawtypes")
public List top(final int n) {
return N.top((Collection) coll, n);
}
public List top(final int n, final Comparator super T> cmp) {
return N.top(coll, n, cmp);
}
/**
* Returns consecutive sub lists of this list, each of the same size (the final list may be smaller),
* or an empty List if the specified list is null or empty.
*
* @return
*/
public List> split(int size) {
return N.split(coll, size);
}
public List> split(final Predicate super T> predicate) {
N.requireNonNull(predicate);
if (N.isNullOrEmpty(coll)) {
return new ArrayList<>();
}
final BiFunction predicate2 = new BiFunction() {
@Override
public Boolean apply(T t, Object u) {
return predicate.test(t);
}
};
return split(null, predicate2, null);
}
public List> split(final U identity, final BiFunction super T, ? super U, Boolean> predicate, final Consumer super U> identityUpdate) {
N.requireNonNull(predicate);
if (N.isNullOrEmpty(coll)) {
return new ArrayList<>();
}
final List> res = new ArrayList<>();
final Iterator elements = iterator();
T next = (T) N.NULL_MASK;
boolean preCondition = false;
while (next != N.NULL_MASK || elements.hasNext()) {
final List piece = new ArrayList<>();
if (next == N.NULL_MASK) {
next = elements.next();
}
while (next != N.NULL_MASK) {
if (piece.size() == 0) {
piece.add(next);
preCondition = predicate.apply(next, identity);
next = elements.hasNext() ? elements.next() : (T) N.NULL_MASK;
} else if (predicate.apply(next, identity) == preCondition) {
piece.add(next);
next = elements.hasNext() ? elements.next() : (T) N.NULL_MASK;
} else {
if (identityUpdate != null) {
identityUpdate.accept(identity);
}
break;
}
}
res.add(piece);
}
return res;
}
/**
*
* @param n
* @return
*/
@SuppressWarnings("rawtypes")
public Pair, List> splitAt(final int n) {
N.checkArgument(n >= 0, "'n' can't be negative: ", n);
List left = null;
List right = null;
if (N.isNullOrEmpty(coll)) {
left = new ArrayList<>();
right = new ArrayList<>();
} else if (n == 0) {
left = new ArrayList<>();
right = new ArrayList<>(coll);
} else if (n >= coll.size()) {
left = new ArrayList<>();
right = new ArrayList<>(coll);
} else if (coll instanceof List) {
left = new ArrayList<>(((List) coll).subList(0, n));
right = new ArrayList<>(((List) coll).subList(n, size()));
} else {
left = new ArrayList<>(slice(0, n));
right = new ArrayList<>(slice(n, size()));
}
return Pair.of(left, right);
}
public Pair, List> splitBy(final Predicate super T> predicate) {
N.requireNonNull(predicate);
final List left = new ArrayList<>();
final List