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

com.landawn.abacus.util.Seq Maven / Gradle / Ivy

There is a newer version: 1.2.9
Show newest version
/*
 * 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.Deque;
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.BinaryOperator;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
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 { @SuppressWarnings("rawtypes") private static final Seq EMPTY = new Seq<>(Collections.EMPTY_LIST); /** * 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) { if (N.isNullOrEmpty(a)) { return EMPTY; } 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 */ public static Seq of(Collection c) { if (N.isNullOrEmpty(c)) { return EMPTY; } return new Seq<>(c); } /** * * @param map * @return */ public static Seq> of(Map map) { if (N.isNullOrEmpty(map)) { return EMPTY; } return of(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(c)) { return true; } else if (N.isNullOrEmpty(coll)) { return false; } return coll.containsAll(c); } public boolean containsAll(Object[] a) { if (N.isNullOrEmpty(a)) { return true; } else if (N.isNullOrEmpty(coll)) { return false; } 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(coll) || 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 cmp) { return size() == 0 ? (Nullable) Nullable.empty() : Nullable.of(N.min(coll, cmp)); } @SuppressWarnings("rawtypes") public Nullable minBy(final Function keyExtractor) { return min(Fn.comparingBy(keyExtractor)); } @SuppressWarnings("rawtypes") public Nullable max() { return size() == 0 ? (Nullable) Nullable.empty() : Nullable.of((T) N.max((Collection) coll)); } public Nullable max(Comparator cmp) { return size() == 0 ? (Nullable) Nullable.empty() : Nullable.of(N.max(coll, cmp)); } @SuppressWarnings("rawtypes") public Nullable maxBy(final Function keyExtractor) { return max(Fn.comparingBy(keyExtractor)); } @SuppressWarnings("rawtypes") public Nullable median() { return size() == 0 ? (Nullable) Nullable.empty() : Nullable.of((T) N.median((Collection) coll)); } public Nullable median(Comparator cmp) { return size() == 0 ? (Nullable) Nullable.empty() : Nullable.of(N.median(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 cmp) { return size() < k ? (Nullable) Nullable.empty() : Nullable.of(N.kthLargest(coll, k, cmp)); } public int sumInt() { if (N.isNullOrEmpty(coll)) { return 0; } return sumInt((ToIntFunction) Fn.numToInt()); } public int sumInt(final Try.ToIntFunction mapper) throws E { if (N.isNullOrEmpty(coll)) { return 0; } return N.sumInt(coll, mapper); } public long sumLong() { if (N.isNullOrEmpty(coll)) { return 0L; } return sumLong((ToLongFunction) Fn.numToLong()); } public long sumLong(final Try.ToLongFunction mapper) throws E { if (N.isNullOrEmpty(coll)) { return 0L; } return N.sumLong(coll, mapper); } public double sumDouble() { if (N.isNullOrEmpty(coll)) { return 0D; } return sumDouble((ToDoubleFunction) Fn.numToDouble()); } public double sumDouble(final Try.ToDoubleFunction mapper) throws E { if (N.isNullOrEmpty(coll)) { return 0L; } return N.sumDouble(coll, mapper); } public OptionalDouble averageInt() { if (N.isNullOrEmpty(coll)) { return OptionalDouble.empty(); } return averageInt((ToIntFunction) Fn.numToInt()); } public OptionalDouble averageInt(final Try.ToIntFunction mapper) throws E { return N.averageInt(coll, mapper); } public OptionalDouble averageLong() { if (N.isNullOrEmpty(coll)) { return OptionalDouble.empty(); } return averageLong((ToLongFunction) Fn.numToLong()); } public OptionalDouble averageLong(final Try.ToLongFunction mapper) throws E { return N.averageLong(coll, mapper); } public OptionalDouble averageDouble() { if (N.isNullOrEmpty(coll)) { return OptionalDouble.empty(); } return averageDouble((ToDoubleFunction) Fn.numToDouble()); } public OptionalDouble averageDouble(final Try.ToDoubleFunction mapper) throws E { return N.averageDouble(coll, mapper); } public void foreach(final Try.Consumer action) throws E { N.forEach(coll, action); } // public void forEach(int fromIndex, final int toIndex, final Consumer action) throws E { // N.forEach(coll, fromIndex, toIndex, action); // } public void forEach(final Try.IndexedConsumer action) throws E { N.forEach(coll, action); } // public void forEach(int fromIndex, final int toIndex, final IndexedConsumer action) throws E { // N.forEach(coll, fromIndex, toIndex, action); // } public R forEach(final R seed, Try.BiFunction accumulator, final Try.BiPredicate conditionToBreak) throws E, E2 { return N.forEach(coll, seed, accumulator, conditionToBreak); } // public R forEach(int fromIndex, final int toIndex, final R seed, final BiFunction accumulator, // final BiPredicate conditionToBreak) throws E { // 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 Try.IndexedBiFunction accumulator, final Try.BiPredicate conditionToBreak) throws E, E2 { return N.forEach(coll, seed, accumulator, conditionToBreak); } public void forEach(final Try.Function, E> flatMapper, final Try.BiConsumer action) throws E, E2 { N.forEach(coll, flatMapper, action); } public void forEach( final Try.Function, E> flatMapper, final Try.Function, E2> flatMapper2, final Try.TriConsumer action) throws E, E2, E3 { N.forEach(coll, flatMapper, flatMapper2, action); } // public void forEachNonNull(final Consumer action) throws E { // N.forEachNonNull(coll, action); // } public void forEachNonNull(final Try.Function, E> flatMapper, final Try.BiConsumer action) throws E, E2 { N.forEachNonNull(coll, flatMapper, action); } public void forEachNonNull( final Try.Function, E> flatMapper, final Try.Function, E2> flatMapper2, final Try.TriConsumer action) throws E, E2, E3 { N.forEachNonNull(coll, flatMapper, flatMapper2, action); } public void forEachPair(final Try.BiConsumer action) throws E { forEachPair(action, 1); } public void forEachPair(final Try.BiConsumer action, final int increment) throws E { 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 Try.TriConsumer action) throws E { forEachTriple(action, 1); } public void forEachTriple(final Try.TriConsumer action, final int increment) throws E { 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 conditionToBreak) throws E { // 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(Try.Predicate predicate) throws E { if (size() == 0) { return Nullable.empty(); } for (T e : coll) { if (predicate.test(e)) { return Nullable.of(e); } } return Nullable.empty(); } public Nullable findLast(Try.Predicate predicate) throws E { 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 if (coll instanceof Deque) { final Iterator iter = ((Deque) coll).descendingIterator(); T next = null; while (iter.hasNext()) { if (predicate.test((next = iter.next()))) { return Nullable.of(next); } } return Nullable.empty(); } else { final T[] a = (T[]) coll.toArray(); for (int i = a.length - 1; i >= 0; i--) { if (predicate.test(a[i])) { return Nullable.of(a[i]); } } return Nullable.empty(); } } public OptionalInt findFirstIndex(Try.Predicate predicate) throws E { 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(Try.Predicate predicate) throws E { 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 if (coll instanceof Deque) { final Iterator iter = ((Deque) coll).descendingIterator(); for (int i = coll.size() - 1; iter.hasNext(); i--) { if (predicate.test(iter.next())) { return OptionalInt.of(i); } } return OptionalInt.empty(); } else { final T[] a = (T[]) coll.toArray(); for (int i = a.length - 1; i >= 0; i--) { if (predicate.test(a[i])) { return OptionalInt.of(i); } } return OptionalInt.empty(); } } public Nullable findFirstOrLast(final Try.Predicate predicateForFirst, final Try.Predicate predicateForLast) throws E, E2 { if (N.isNullOrEmpty(coll)) { return Nullable. empty(); } final Nullable res = findFirst(predicateForFirst); return res.isPresent() ? res : findLast(predicateForLast); } public OptionalInt findFirstOrLastIndex(final Try.Predicate predicateForFirst, final Try.Predicate predicateForLast) throws E, E2 { if (N.isNullOrEmpty(coll)) { return OptionalInt.empty(); } final OptionalInt res = findFirstIndex(predicateForFirst); return res.isPresent() ? res : findLastIndex(predicateForLast); } public Pair, Nullable> findFirstAndLast(final Try.Predicate predicate) throws E { return findFirstAndLast(predicate, predicate); } public Pair, Nullable> findFirstAndLast(final Try.Predicate predicateForFirst, final Try.Predicate predicateForLast) throws E, E2 { if (N.isNullOrEmpty(coll)) { return Pair.of(Nullable. empty(), Nullable. empty()); } return Pair.of(findFirst(predicateForFirst), findLast(predicateForLast)); } public Pair findFirstAndLastIndex(final Try.Predicate predicate) throws E { return findFirstAndLastIndex(predicate, predicate); } public Pair findFirstAndLastIndex(final Try.Predicate predicateForFirst, final Try.Predicate predicateForLast) throws E, E2 { if (N.isNullOrEmpty(coll)) { return Pair.of(OptionalInt.empty(), OptionalInt.empty()); } return Pair.of(findFirstIndex(predicateForFirst), findLastIndex(predicateForLast)); } public boolean allMatch(Try.Predicate filter) throws E { if (N.isNullOrEmpty(coll)) { return true; } for (T e : coll) { if (filter.test(e) == false) { return false; } } return true; } public boolean anyMatch(Try.Predicate filter) throws E { if (N.isNullOrEmpty(coll)) { return false; } for (T e : coll) { if (filter.test(e)) { return true; } } return false; } public boolean noneMatch(Try.Predicate filter) throws E { 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(Try.Predicate filter) throws E { return N.count(coll, filter); } public List filter(Try.Predicate filter) throws E { return N.filter(coll, filter); } public List filter(Try.Predicate filter, final int max) throws E { return N.filter(coll, filter, max); } public List filter(final U seed, final Try.BiPredicate predicate) throws E { return filter(new Try.Predicate() { @Override public boolean test(T value) throws E { return predicate.test(value, seed); } }); } public List takeWhile(Try.Predicate filter) throws E { 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 Try.BiPredicate predicate) throws E { return takeWhile(new Try.Predicate() { @Override public boolean test(T value) throws E { return predicate.test(value, seed); } }); } public List takeWhileInclusive(Try.Predicate filter) throws E { 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 Try.BiPredicate predicate) throws E { return takeWhileInclusive(new Try.Predicate() { @Override public boolean test(T value) throws E { return predicate.test(value, seed); } }); } public List dropWhile(Try.Predicate filter) throws E { 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 Try.BiPredicate predicate) throws E { return dropWhile(new Try.Predicate() { @Override public boolean test(T value) throws E { return predicate.test(value, seed); } }); } public List skipUntil(final Try.Predicate filter) throws E { return dropWhile(new Try.Predicate() { @Override public boolean test(T value) throws E { return !filter.test(value); } }); } public List skipUntil(final U seed, final Try.BiPredicate predicate) throws E { return dropWhile(new Try.Predicate() { @Override public boolean test(T value) throws E { return !predicate.test(value, seed); } }); } public List map(final Try.Function func) throws E { return N.map(coll, func); } public BooleanList mapToBoolean(final Try.ToBooleanFunction func) throws E { return N.mapToBoolean(coll, func); } public CharList mapToChar(final Try.ToCharFunction func) throws E { return N.mapToChar(coll, func); } public ByteList mapToByte(final Try.ToByteFunction func) throws E { return N.mapToByte(coll, func); } public ShortList mapToShort(final Try.ToShortFunction func) throws E { return N.mapToShort(coll, func); } public IntList mapToInt(final Try.ToIntFunction func) throws E { return N.mapToInt(coll, func); } public LongList mapToLong(final Try.ToLongFunction func) throws E { return N.mapToLong(coll, func); } public FloatList mapToFloat(final Try.ToFloatFunction func) throws E { return N.mapToFloat(coll, func); } public DoubleList mapToDouble(final Try.ToDoubleFunction func) throws E { return N.mapToDouble(coll, func); } public List flatMap(final Try.Function, E> func) throws E { 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 flattMap(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToBoolean(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToChar(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToByte(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToShort(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToInt(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToLong(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToFloat(final Try.Function func) throws E { 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 Try.Function, E> func) throws E { 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 flattMapToDouble(final Try.Function func) throws E { 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 Try.Function, E> mapper, final Try.BiFunction func) throws E, E2 { 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 Try.Function, E> mapper2, final Try.Function, E2> mapper3, final Try.TriFunction func) throws E, E2, E3 { 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 Try.BiPredicate collapsible, final Try.BiFunction mergeFunction) throws E, E2 { 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 Try.BiPredicate collapsible, final Collector collector) throws E { 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 Try.BiFunction accumulator) throws E { 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 Try.BiFunction accumulator) throws E { 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(Try.BinaryOperator accumulator) throws E { 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, Try.BiFunction accumulator) throws E { 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 Try.BiConsumer accumulator) throws E { final R result = supplier.get(); if (N.notNullOrEmpty(coll)) { for (T e : coll) { accumulator.accept(result, e); } } return result; } public R collect(final Collector 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 Try.Function finisher) throws E { return finisher.apply(collect(downstream)); } @SafeVarargs public final List append(T... a) { if (N.isNullOrEmpty(a)) { return toList(); } return append(Arrays.asList(a)); } public List append(final Collection c) { return Seq.concat(this, c); } @SafeVarargs public final List prepend(T... a) { if (N.isNullOrEmpty(a)) { return toList(); } return prepend(Arrays.asList(a)); } public List prepend(final Collection c) { return Seq.concat(c, this); } public List merge(final Collection b, final Try.BiFunction nextSelector) throws E { return Seq.merge(this, b, nextSelector); } public List zipWith(final Collection b, final Try.BiFunction zipFunction) throws E { return Seq.zip(this, b, zipFunction); } public List zipWith(final Collection b, final T valueForNoneA, final B valueForNoneB, final Try.BiFunction zipFunction) throws E { return Seq.zip(this, b, valueForNoneA, valueForNoneB, zipFunction); } public List zipWith(final Collection b, final Collection c, final Try.TriFunction zipFunction) throws E { 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 Try.TriFunction zipFunction) throws E { 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 Try.Function keyExtractor) throws E { 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 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 Try.Predicate predicate) throws E { N.requireNonNull(predicate); if (N.isNullOrEmpty(coll)) { return new ArrayList<>(); } final Try.BiPredicate predicate2 = new Try.BiPredicate() { @Override public boolean test(T t, Object u) throws E { return predicate.test(t); } }; return split(null, predicate2, Fn.doNothing()); } public List> split(final U identity, final Try.BiPredicate predicate, final Try.Consumer identityUpdate) throws E, E2 { 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.test(next, identity); next = elements.hasNext() ? elements.next() : (T) N.NULL_MASK; } else if (predicate.test(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 Try.Predicate predicate) throws E { N.requireNonNull(predicate); final List left = new ArrayList<>(); final List right = new ArrayList<>(); if (N.notNullOrEmpty(coll)) { final Iterator iter = iterator(); T next = (T) N.NULL_MASK; while (iter.hasNext() && predicate.test((next = iter.next()))) { left.add(next); next = (T) N.NULL_MASK; } if (next != N.NULL_MASK) { right.add(next); } while (iter.hasNext()) { right.add(iter.next()); } } return Pair.of(left, right); } public List> sliding(final int windowSize) { return sliding(windowSize, 1); } public List> sliding(final int windowSize, final int increment) { N.checkArgument(windowSize > 0 && increment > 0, "'windowSize'=%s and 'increment'=%s must not be less than 1", windowSize, increment); if (N.isNullOrEmpty(coll)) { return new ArrayList<>(); } final Iterator iter = coll.iterator(); final List> result = new ArrayList<>(coll.size() <= windowSize ? 1 : (1 + (coll.size() - windowSize)) / increment); while (iter.hasNext()) { if (increment > windowSize && result.size() > 0) { int skipNum = increment - windowSize; while (skipNum-- > 0 && iter.hasNext()) { iter.next(); } if (iter.hasNext() == false) { break; } } final List window = new ArrayList<>(windowSize); int cnt = 0; if (increment < windowSize && result.size() > 0) { final List prev = result.get(result.size() - 1); cnt = windowSize - increment; if (cnt <= 8) { for (int i = windowSize - cnt; i < windowSize; i++) { window.add(prev.get(i)); } } else { window.addAll(prev.subList(windowSize - cnt, windowSize)); } } while (cnt++ < windowSize && iter.hasNext()) { window.add(iter.next()); } result.add(window); } return result; } public String join() { return join(N.ELEMENT_SEPARATOR); } public String join(final char delimiter) { return N.join(coll, delimiter); } public String join(final String delimiter) { return N.join(coll, delimiter); } @Override public boolean isEmpty() { return coll == null || coll.isEmpty(); } @Override public int size() { return coll == null ? 0 : coll.size(); } @Override public Object[] toArray() { return coll == null ? N.EMPTY_OBJECT_ARRAY : coll.toArray(); } @Override public
A[] toArray(A[] a) { return coll == null ? a : coll.toArray(a); } public List toList() { return coll == null ? new ArrayList() : new ArrayList(coll); } public > R toList(final IntFunction supplier) { final R result = supplier.apply(size()); if (N.notNullOrEmpty(coll)) { result.addAll(coll); } return result; } public Set toSet() { return coll == null ? new HashSet() : new HashSet(coll); } public > R toSet(final IntFunction supplier) { final R result = supplier.apply(size()); if (N.notNullOrEmpty(coll)) { result.addAll(coll); } return result; } public Multiset toMultiset() { final Multiset result = new Multiset<>(N.initHashCapacity(size())); if (N.notNullOrEmpty(coll)) { result.addAll(coll); } return result; } public Multiset toMultiset(final IntFunction> supplier) { final Multiset result = supplier.apply(N.initHashCapacity(size())); if (N.notNullOrEmpty(coll)) { result.addAll(coll); } return result; } public Map toMap(Try.Function keyExtractor, Try.Function valueMapper) throws E, E2 { final Supplier> mapFactory = Fn.Suppliers.ofMap(); return toMap(keyExtractor, valueMapper, mapFactory); } public , E extends Exception, E2 extends Exception> M toMap(Try.Function keyExtractor, Try.Function valueMapper, Supplier mapFactory) throws E, E2 { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toMap(keyExtractor, valueMapper, mergeFunction, mapFactory); } public Map toMap(Try.Function keyExtractor, Try.Function valueMapper, Try.BinaryOperator mergeFunction) throws E, E2, E3 { final Supplier> mapFactory = Fn.Suppliers.ofMap(); return toMap(keyExtractor, valueMapper, mergeFunction, mapFactory); } public , E extends Exception, E2 extends Exception, E3 extends Exception> M toMap( Try.Function keyExtractor, Try.Function valueMapper, Try.BinaryOperator mergeFunction, Supplier mapFactory) throws E, E2, E3 { final M result = mapFactory.get(); final Iterator iter = iterator(); T element = null; while (iter.hasNext()) { element = iter.next(); merge(result, keyExtractor.apply(element), valueMapper.apply(element), mergeFunction); } return result; } public Map toMap(Try.Function classifier, Collector downstream) throws E { final Supplier> mapFactory = Fn.Suppliers.ofMap(); return toMap(classifier, downstream, mapFactory); } public , E extends Exception> M toMap(final Try.Function classifier, final Collector downstream, final Supplier mapFactory) throws E { final M result = mapFactory.get(); final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Map intermediate = (Map) result; final Iterator iter = iterator(); K key = null; A v = null; T element = null; while (iter.hasNext()) { element = iter.next(); key = N.requireNonNull(classifier.apply(element), "element cannot be mapped to a null key"); if ((v = intermediate.get(key)) == null) { if ((v = downstreamSupplier.get()) != null) { intermediate.put(key, v); } } downstreamAccumulator.accept(v, element); } final BiFunction function = new BiFunction() { @Override public A apply(K k, A v) { return (A) downstream.finisher().apply(v); } }; replaceAll(intermediate, function); return result; } public Map toMap(Try.Function classifier, Try.Function valueMapper, Collector downstream) throws E, E2 { final Supplier> mapFactory = Fn.Suppliers.ofMap(); return toMap(classifier, valueMapper, downstream, mapFactory); } public , E extends Exception, E2 extends Exception> M toMap(final Try.Function classifier, Try.Function valueMapper, final Collector downstream, final Supplier mapFactory) throws E, E2 { final M result = mapFactory.get(); final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Map intermediate = (Map) result; final Iterator iter = iterator(); K key = null; A v = null; T element = null; while (iter.hasNext()) { element = iter.next(); key = N.requireNonNull(classifier.apply(element), "element cannot be mapped to a null key"); if ((v = intermediate.get(key)) == null) { if ((v = downstreamSupplier.get()) != null) { intermediate.put(key, v); } } downstreamAccumulator.accept(v, valueMapper.apply(element)); } final BiFunction function = new BiFunction() { @Override public A apply(K k, A v) { return (A) downstream.finisher().apply(v); } }; replaceAll(intermediate, function); return result; } public Map> groupTo(Try.Function classifier) throws E { final Supplier>> mapFactory = Fn.Suppliers.ofMap(); return groupTo(classifier, mapFactory); } public >, E extends Exception> M groupTo(Try.Function classifier, Supplier mapFactory) throws E { final Collector> downstream = Collectors.toList(); return toMap(classifier, downstream, mapFactory); } public Map> groupTo(Try.Function keyExtractor, Try.Function valueMapper) throws E, E2 { final Supplier>> mapFactory = Fn.Suppliers.ofMap(); return groupTo(keyExtractor, valueMapper, mapFactory); } public >, E extends Exception, E2 extends Exception> M groupTo(Try.Function keyExtractor, Try.Function valueMapper, Supplier mapFactory) throws E, E2 { final M result = mapFactory.get(); final Iterator iter = iterator(); T element = null; K key = null; List values = null; while (iter.hasNext()) { element = iter.next(); key = keyExtractor.apply(element); values = result.get(key); if (values == null) { values = new ArrayList(); result.put(key, values); } values.add(valueMapper.apply(element)); } return result; } /** * * @param keyExtractor * @return */ public ListMultimap toMultimap(Try.Function keyExtractor) throws E { final ListMultimap result = N.newListMultimap(); if (N.isNullOrEmpty(coll)) { return result; } for (T e : coll) { result.put(keyExtractor.apply(e), e); } return result; } public , M extends Multimap, E extends Exception> M toMultimap(Try.Function keyExtractor, Supplier mapFactory) throws E { final M result = mapFactory.get(); if (N.isNullOrEmpty(coll)) { return result; } for (T e : coll) { result.put(keyExtractor.apply(e), e); } return result; } /** * * @param keyExtractor * @param valueMapper * @return */ public ListMultimap toMultimap(Try.Function keyExtractor, Try.Function valueMapper) throws E, E2 { final ListMultimap result = N.newListMultimap(); if (N.isNullOrEmpty(coll)) { return result; } for (T e : coll) { result.put(keyExtractor.apply(e), valueMapper.apply(e)); } return result; } public , M extends Multimap, E extends Exception, E2 extends Exception> M toMultimap( Try.Function keyExtractor, Try.Function valueMapper, Supplier mapFactory) throws E, E2 { final M result = mapFactory.get(); if (N.isNullOrEmpty(coll)) { return result; } for (T e : coll) { result.put(keyExtractor.apply(e), valueMapper.apply(e)); } return result; } /** * * The time complexity is O(n + m) : n is the size of this Seq and m is the size of specified collection b. * * @param b * @param leftKeyMapper * @param rightKeyMapper * @return * @see sql join */ public List> innerJoin(final Collection b, final Try.Function leftKeyMapper, final Try.Function rightKeyMapper) throws E, E2 { final List> result = new ArrayList<>(N.min(9, size(), b.size())); if (N.isNullOrEmpty(coll) || N.isNullOrEmpty(b)) { return result; } final ListMultimap rightKeyMap = ListMultimap.from(b, rightKeyMapper); for (T left : coll) { final List rights = rightKeyMap.get(leftKeyMapper.apply(left)); if (N.notNullOrEmpty(rights)) { for (U right : rights) { result.add(Pair.of(left, right)); } } } return result; } /** * * The time complexity is O(n * m) : n is the size of this Seq and m is the size of specified collection b. * * @param b * @param predicate * @return * @see List> fullJoin(final Collection b, final Try.Function leftKeyMapper, final Try.Function rightKeyMapper) throws E, E2 { final List> result = new ArrayList<>(N.max(9, size(), b.size())); if (N.isNullOrEmpty(coll)) { for (T left : coll) { result.add(Pair.of(left, (U) null)); } } else if (N.isNullOrEmpty(b)) { for (U right : b) { result.add(Pair.of((T) null, right)); } } else { final ListMultimap rightKeyMap = ListMultimap.from(b, rightKeyMapper); final Map joinedRights = new IdentityHashMap<>(); for (T left : coll) { final List rights = rightKeyMap.get(leftKeyMapper.apply(left)); if (N.notNullOrEmpty(rights)) { for (U right : rights) { result.add(Pair.of(left, right)); joinedRights.put(right, right); } } else { result.add(Pair.of(left, (U) null)); } } for (U right : b) { if (joinedRights.containsKey(right) == false) { result.add(Pair.of((T) null, right)); } } } return result; } /** * The time complexity is O(n * m) : n is the size of this Seq and m is the size of specified collection b. * * @param b * @param predicate * @return * @see List> leftJoin(final Collection b, final Try.Function leftKeyMapper, final Try.Function rightKeyMapper) throws E, E2 { final List> result = new ArrayList<>(size()); if (N.isNullOrEmpty(coll)) { return result; } else if (N.isNullOrEmpty(b)) { for (T left : coll) { result.add(Pair.of(left, (U) null)); } } else { final ListMultimap rightKeyMap = ListMultimap.from(b, rightKeyMapper); for (T left : coll) { final List rights = rightKeyMap.get(leftKeyMapper.apply(left)); if (N.notNullOrEmpty(rights)) { for (U right : rights) { result.add(Pair.of(left, right)); } } else { result.add(Pair.of(left, (U) null)); } } } return result; } /** * The time complexity is O(n * m) : n is the size of this Seq and m is the size of specified collection b. * * @param b * @param predicate * @return * @see List> rightJoin(final Collection b, final Try.Function leftKeyMapper, final Try.Function rightKeyMapper) throws E, E2 { final List> result = new ArrayList<>(b.size()); if (N.isNullOrEmpty(b)) { return result; } else if (N.isNullOrEmpty(coll)) { for (U right : b) { result.add(Pair.of((T) null, right)); } } else { final ListMultimap leftKeyMap = ListMultimap.from(coll, leftKeyMapper); for (U right : b) { final List lefts = leftKeyMap.get(rightKeyMapper.apply(right)); if (N.notNullOrEmpty(lefts)) { for (T left : lefts) { result.add(Pair.of(left, right)); } } else { result.add(Pair.of((T) null, right)); } } } return result; } /** * The time complexity is O(n * m) : n is the size of this Seq and m is the size of specified collection b. * * @param b * @param predicate * @return * @see (); } final List result = new ArrayList<>(c.size() * n); for (int i = 0; i < n; i++) { result.addAll(c); } return result; } /** * Repeats the elements in the specified Collection one by one. * *
     * 
     * Seq.nRepeat(N.asList(1, 2, 3), 2) => [1, 1, 2, 2, 3, 3]
     * 
     * 
* * @param c * @param n * @return */ public static List nRepeat(final Collection c, final int n) { N.checkArgument(n >= 0, "'n' can't be negative: %s", n); if (n == 0 || N.isNullOrEmpty(c)) { return new ArrayList(); } final List result = new ArrayList<>(c.size() * n); for (T e : c) { for (int i = 0; i < n; i++) { result.add(e); } } return result; } /** * *
     * 
     * Seq.repeatToSize(N.asList(1, 2, 3), 5) => [1, 2, 3, 1, 2]
     * 
     * 
* * @param c * @param size * @return */ public static List repeatToSize(final Collection c, final int size) { N.checkArgument(size >= 0, "'size' can't be negative: %s", size); N.checkArgument(size == 0 || N.notNullOrEmpty(c), "Collection can't be empty or null when size > 0"); if (size == 0 || N.isNullOrEmpty(c)) { return new ArrayList(); } final List result = new ArrayList<>(size); while (result.size() < size) { if (c.size() <= size - result.size()) { result.addAll(c); } else { final Iterator iter = c.iterator(); for (int i = 0, len = size - result.size(); i < len; i++) { result.add(iter.next()); } } } return result; } /** * Repeats the elements in the specified Collection one by one till reach the specified size. * *
     * 
     * Seq.nRepeatToSize(N.asList(1, 2, 3), 5) => [1, 1, 2, 2, 3]
     * 
     * 
* * @param c * @param size * @return */ public static List nRepeatToSize(final Collection c, final int size) { N.checkArgument(size >= 0, "'size' can't be negative: %s", size); N.checkArgument(size == 0 || N.notNullOrEmpty(c), "Collection can't be empty or null when size > 0"); if (size == 0 || N.isNullOrEmpty(c)) { return new ArrayList(); } final int n = size / c.size(); int mod = size % c.size(); final List result = new ArrayList<>(size); for (T e : c) { for (int i = 0, len = mod-- > 0 ? n + 1 : n; i < len; i++) { result.add(e); } if (result.size() == size) { break; } } return result; } public static void reverse(final Collection c) { if (N.isNullOrEmpty(c) && c.size() < 2) { return; } if (c instanceof List) { N.reverse((List) c); } else { final Object[] tmp = c.toArray(); N.reverse(tmp); c.clear(); c.addAll((List) Arrays.asList(tmp)); } } public static void rotate(final Collection c, final int distance) { if (N.isNullOrEmpty(c) && c.size() < 2) { return; } if (c instanceof List) { N.rotate((List) c, distance); } else { final Object[] tmp = c.toArray(); N.rotate(tmp, distance); c.clear(); c.addAll((List) Arrays.asList(tmp)); } } public static void shuffle(final Collection c) { if (N.isNullOrEmpty(c) && c.size() < 2) { return; } if (c instanceof List) { N.shuffle((List) c); } else { final Object[] tmp = c.toArray(); N.shuffle(tmp); c.clear(); c.addAll((List) Arrays.asList(tmp)); } } public static void shuffle(final Collection c, final Random rnd) { if (N.isNullOrEmpty(c) && c.size() < 2) { return; } if (c instanceof List) { N.shuffle((List) c, rnd); } else { final Object[] tmp = c.toArray(); N.shuffle(tmp, rnd); c.clear(); c.addAll((List) Arrays.asList(tmp)); } } // public ListBuilder __() { // return Builder.of(this); // } // // public ListBuilder __(Consumer, E> func) throws E { // return Builder.of(this).__(func); // } public static boolean disjoint(final Object[] a, final Object[] b) { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) { return true; } return a.length >= b.length ? disjoint(Arrays.asList(a), N.asSet(b)) : disjoint(N.asSet(a), Arrays.asList(b)); } /** * Returns {@code true} if the two specified arrays have no elements in common. * * @param a * @param b * @return {@code true} if the two specified arrays have no elements in common. * @see Collections#disjoint(Collection, Collection) */ public static boolean disjoint(final Collection c1, final Collection c2) { if (N.isNullOrEmpty(c1) || N.isNullOrEmpty(c2)) { return true; } if (c1 instanceof Set || (c2 instanceof Set == false && c1.size() > c2.size())) { for (Object e : c2) { if (c1.contains(e)) { return false; } } } else { for (Object e : c1) { if (c2.contains(e)) { return false; } } } return true; } public static List concat(final T[] a, final T[] b) { if (N.isNullOrEmpty(a)) { if (N.isNullOrEmpty(b)) { return new ArrayList<>(); } else { final List res = new ArrayList<>(b.length); res.addAll(Arrays.asList(b)); return res; } } else { final List res = new ArrayList<>(a.length + (b == null ? 0 : b.length)); res.addAll(Arrays.asList(a)); if (N.notNullOrEmpty(b)) { res.addAll(Arrays.asList(b)); } return res; } } @SafeVarargs public static List concat(final T[]... a) { if (N.isNullOrEmpty(a)) { return new ArrayList<>(); } int count = 0; for (T[] e : a) { if (N.notNullOrEmpty(e)) { count += e.length; } } final List result = new ArrayList<>(count); for (T[] e : a) { if (N.notNullOrEmpty(e)) { if (a.length < 9) { for (T t : e) { result.add(t); } } else { result.addAll(Arrays.asList(e)); } } } return result; } public static List concat(final Collection a, final Collection b) { return N.concat(a, b); } @SafeVarargs public static List concat(final Collection... a) { if (N.isNullOrEmpty(a)) { return new ArrayList<>(); } return concat(Arrays.asList(a)); } public static List concat(final Collection> c) { if (N.isNullOrEmpty(c)) { return new ArrayList<>(); } int count = 0; for (Collection e : c) { if (N.notNullOrEmpty(e)) { count += e.size(); } } final List result = new ArrayList<>(count); for (Collection e : c) { if (N.notNullOrEmpty(e)) { result.addAll(e); } } return result; } /** * * @param a * @return * @see Iterators#concat(Object[]...) */ @SafeVarargs public static ObjIterator iterate(final T[]... a) { return Iterators.concat(a); } /** * * @param a * @return * @see Iterators#concat(Collection) */ @SafeVarargs public static ObjIterator iterate(final Collection... a) { return Iterators.concat(a); } /** * * @param c * @return * @see Iterators#concatt(Collection) */ public static ObjIterator iterate(final Collection> c) { return Iterators.concatt(c); } public static List merge(final T[] a, final T[] b, final Try.BiFunction nextSelector) throws E { if (N.isNullOrEmpty(a)) { return N.isNullOrEmpty(b) ? new ArrayList() : N.asList(b); } else if (N.isNullOrEmpty(b)) { return N.asList(a); } final List result = new ArrayList<>(a.length + b.length); final int lenA = a.length; final int lenB = b.length; int cursorA = 0; int cursorB = 0; while (cursorA < lenA || cursorB < lenB) { if (cursorA < lenA) { if (cursorB < lenB) { if (nextSelector.apply(a[cursorA], b[cursorB]) == Nth.FIRST) { result.add(a[cursorA++]); } else { result.add(b[cursorB++]); } } else { result.add(a[cursorA++]); } } else { result.add(b[cursorB++]); } } return result; } public static List merge(final Collection a, final Collection b, final Try.BiFunction nextSelector) throws E { if (N.isNullOrEmpty(a)) { return N.isNullOrEmpty(b) ? new ArrayList() : new ArrayList(b); } else if (N.isNullOrEmpty(b)) { return new ArrayList(a); } final List result = new ArrayList<>(a.size() + b.size()); final Iterator iterA = a.iterator(); final Iterator iterB = b.iterator(); T nextA = null; T nextB = null; boolean hasNextA = false; boolean hasNextB = false; while (hasNextA || hasNextB || iterA.hasNext() || iterB.hasNext()) { if (hasNextA) { if (iterB.hasNext()) { if (nextSelector.apply(nextA, (nextB = iterB.next())) == Nth.FIRST) { hasNextA = false; hasNextB = true; result.add(nextA); } else { result.add(nextB); } } else { hasNextA = false; result.add(nextA); } } else if (hasNextB) { if (iterA.hasNext()) { if (nextSelector.apply((nextA = iterA.next()), nextB) == Nth.FIRST) { result.add(nextA); } else { hasNextA = true; hasNextB = false; result.add(nextB); } } else { hasNextB = false; result.add(nextB); } } else if (iterA.hasNext()) { if (iterB.hasNext()) { if (nextSelector.apply((nextA = iterA.next()), (nextB = iterB.next())) == Nth.FIRST) { hasNextB = true; result.add(nextA); } else { hasNextA = true; result.add(nextB); } } else { result.add(iterA.next()); } } else { result.add(iterB.next()); } } return result; } public static List zip(final A[] a, final B[] b, final Try.BiFunction zipFunction) throws E { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) { return new ArrayList<>(); } final int minLen = N.min(a.length, b.length); final List result = new ArrayList<>(minLen); for (int i = 0; i < minLen; i++) { result.add(zipFunction.apply(a[i], b[i])); } return result; } public static List zip(final Collection
a, final Collection b, final Try.BiFunction zipFunction) throws E { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) { return new ArrayList<>(); } final Iterator iterA = a.iterator(); final Iterator iterB = b.iterator(); final int minLen = N.min(a.size(), b.size()); final List result = new ArrayList<>(minLen); for (int i = 0; i < minLen; i++) { result.add(zipFunction.apply(iterA.next(), iterB.next())); } return result; } public static List zip(final A[] a, final B[] b, final C[] c, final Try.TriFunction zipFunction) throws E { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b) || N.isNullOrEmpty(c)) { return new ArrayList<>(); } final int minLen = N.min(a.length, b.length, c.length); final List result = new ArrayList<>(minLen); for (int i = 0; i < minLen; i++) { result.add(zipFunction.apply(a[i], b[i], c[i])); } return result; } public static List zip(final Collection a, final Collection b, final Collection c, final Try.TriFunction zipFunction) throws E { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b) || N.isNullOrEmpty(c)) { return new ArrayList<>(); } final Iterator iterA = a.iterator(); final Iterator iterB = b.iterator(); final Iterator iterC = c.iterator(); final int minLen = N.min(a.size(), b.size(), c.size()); final List result = new ArrayList<>(minLen); for (int i = 0; i < minLen; i++) { result.add(zipFunction.apply(iterA.next(), iterB.next(), iterC.next())); } return result; } public static List zip(final A[] a, final B[] b, final A valueForNoneA, final B valueForNoneB, final Try.BiFunction zipFunction) throws E { final int lenA = a == null ? 0 : a.length; final int lenB = b == null ? 0 : b.length; final int maxLen = N.max(lenA, lenB); final List result = new ArrayList<>(maxLen); for (int i = 0; i < maxLen; i++) { result.add(zipFunction.apply(i < lenA ? a[i] : valueForNoneA, i < lenB ? b[i] : valueForNoneB)); } return result; } public static List zip(final Collection a, final Collection b, final A valueForNoneA, final B valueForNoneB, final Try.BiFunction zipFunction) throws E { final Iterator iterA = a == null ? ObjIterator. empty() : a.iterator(); final Iterator iterB = b == null ? ObjIterator. empty() : b.iterator(); final int lenA = a == null ? 0 : a.size(); final int lenB = b == null ? 0 : b.size(); final int maxLen = N.max(lenA, lenB); final List result = new ArrayList<>(maxLen); for (int i = 0; i < maxLen; i++) { result.add(zipFunction.apply(i < lenA ? iterA.next() : valueForNoneA, i < lenB ? iterB.next() : valueForNoneB)); } return result; } public static List zip(final A[] a, final B[] b, final C[] c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Try.TriFunction zipFunction) throws E { final int lenA = a == null ? 0 : a.length; final int lenB = b == null ? 0 : b.length; final int lenC = c == null ? 0 : c.length; final int maxLen = N.max(lenA, lenB, lenC); final List result = new ArrayList<>(maxLen); for (int i = 0; i < maxLen; i++) { result.add(zipFunction.apply(i < lenA ? a[i] : valueForNoneA, i < lenB ? b[i] : valueForNoneB, i < lenC ? c[i] : valueForNoneC)); } return result; } public static List zip(final Collection a, final Collection b, final Collection c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Try.TriFunction zipFunction) throws E { final Iterator iterA = a == null ? ObjIterator. empty() : a.iterator(); final Iterator iterB = b == null ? ObjIterator. empty() : b.iterator(); final Iterator iterC = c == null ? ObjIterator. empty() : c.iterator(); final int lenA = a == null ? 0 : a.size(); final int lenB = b == null ? 0 : b.size(); final int lenC = c == null ? 0 : c.size(); final int maxLen = N.max(lenA, lenB, lenC); final List result = new ArrayList<>(maxLen); for (int i = 0; i < maxLen; i++) { result.add(zipFunction.apply(i < lenA ? iterA.next() : valueForNoneA, i < lenB ? iterB.next() : valueForNoneB, i < lenC ? iterC.next() : valueForNoneC)); } return result; } /** * * @param c * @param unzip the second parameter is an output parameter. * @return */ public static Pair, List> unzip(final Collection c, final Try.BiConsumer, E> unzip) throws E { final int len = c == null ? 0 : c.size(); final List l = new ArrayList(len); final List r = new ArrayList(len); final Pair p = new Pair<>(); if (N.notNullOrEmpty(c)) { for (T e : c) { unzip.accept(e, p); l.add(p.left); r.add(p.right); } } return Pair.of(l, r); } /** * * @param c * @param unzip the second parameter is an output parameter. * @param supplier * @return */ public static , RC extends Collection, E extends Exception> Pair unzip(final Collection c, final Try.BiConsumer, E> unzip, final IntFunction> supplier) throws E { final int len = c == null ? 0 : c.size(); final LC l = (LC) supplier.apply(len); final RC r = (RC) supplier.apply(len); final Pair p = new Pair<>(); if (N.notNullOrEmpty(c)) { for (T e : c) { unzip.accept(e, p); l.add(p.left); r.add(p.right); } } return Pair.of(l, r); } /** * * @param c * @param unzip the second parameter is an output parameter. * @return */ public static Triple, List, List> unzipp(final Collection c, final Try.BiConsumer, E> unzip) throws E { final int len = c == null ? 0 : c.size(); final List l = new ArrayList(len); final List m = new ArrayList(len); final List r = new ArrayList(len); final Triple t = new Triple<>(); if (N.notNullOrEmpty(c)) { for (T e : c) { unzip.accept(e, t); l.add(t.left); m.add(t.middle); r.add(t.right); } } return Triple.of(l, m, r); } /** * * @param c * @param unzip the second parameter is an output parameter. * @param supplier * @return */ public static , MC extends Collection, RC extends Collection, E extends Exception> Triple unzipp( final Collection c, final Try.BiConsumer, E> unzip, final IntFunction> supplier) throws E { final int len = c == null ? 0 : c.size(); final LC l = (LC) supplier.apply(len); final MC m = (MC) supplier.apply(len); final RC r = (RC) supplier.apply(len); final Triple t = new Triple<>(); if (N.notNullOrEmpty(c)) { for (T e : c) { unzip.accept(e, t); l.add(t.left); m.add(t.middle); r.add(t.right); } } return Triple.of(l, m, r); } public static List> rollup(Collection c) { final List> res = new ArrayList<>(); res.add(new ArrayList()); if (N.notNullOrEmpty(c)) { for (T e : c) { final List prev = res.get(res.size() - 1); List cur = new ArrayList<>(prev.size() + 1); cur.addAll(prev); cur.add(e); res.add(cur); } } return res; } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns the set of all possible subsets of {@code set}. For example, * {@code powerSet(ImmutableSet.of(1, 2))} returns the set {@code {{}, * {1}, {2}, {1, 2}}}. * *

Elements appear in these subsets in the same iteration order as they * appeared in the input set. The order in which these subsets appear in the * outer set is undefined. Note that the power set of the empty set is not the * empty set, but a one-element set containing the empty set. * *

The returned set and its constituent sets use {@code equals} to decide * whether two elements are identical, even if the input set uses a different * concept of equivalence. * *

Notes: This is an implementation of the Plain Changes algorithm * for permutations generation, described in Knuth's "The Art of Computer * Programming", Volume 4, Chapter 7, Section 7.2.1.2. * *

If the input list contains equal elements, some of the generated * permutations will be equal. * *

An empty collection has only one permutation, which is an empty list. * * @param elements the original collection whose elements have to be permuted. * @return an immutable {@link Collection} containing all the different * permutations of the original collection. * @throws NullPointerException if the specified collection is null or has any * null elements. * @since 12.0 */ public static Collection> permutations(Collection elements) { return new PermutationCollection(elements); } private static final class PermutationCollection extends AbstractCollection> { final List inputList; PermutationCollection(Collection input) { this.inputList = new ArrayList<>(input); } @Override public int size() { return Maths.factorial(inputList.size()); } @Override public boolean isEmpty() { return false; } @Override public Iterator> iterator() { return PermutationIterator.of(inputList); } @Override public boolean contains(Object obj) { if (obj instanceof Collection) { return isPermutations(inputList, (Collection) obj); } return false; } @Override public String toString() { return "permutations(" + inputList + ")"; } } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns a {@link Collection} of all the permutations of the specified * {@link Iterable}. * *

Notes: This is an implementation of the algorithm for * Lexicographical Permutations Generation, described in Knuth's "The Art of * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The * iteration order follows the lexicographical order. This means that * the first permutation will be in ascending order, and the last will be in * descending order. * *

Duplicate elements are considered equal. For example, the list [1, 1] * will have only one permutation, instead of two. This is why the elements * have to implement {@link Comparable}. * *

An empty iterable has only one permutation, which is an empty list. * *

This method is equivalent to * {@code Collections2.orderedPermutations(list, Ordering.natural())}. * * @param elements the original iterable whose elements have to be permuted. * @return an immutable {@link Collection} containing all the different * permutations of the original iterable. * @throws NullPointerException if the specified iterable is null or has any * null elements. * @since 12.0 */ public static > Collection> orderedPermutations(Collection elements) { return orderedPermutations(elements, Comparators.OBJ_COMPARATOR); } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns a {@link Collection} of all the permutations of the specified * {@link Iterable} using the specified {@link Comparator} for establishing * the lexicographical ordering. * *

Examples:

   {@code
     *
     *   for (List perm : orderedPermutations(asList("b", "c", "a"))) {
     *     println(perm);
     *   }
     *   // -> ["a", "b", "c"]
     *   // -> ["a", "c", "b"]
     *   // -> ["b", "a", "c"]
     *   // -> ["b", "c", "a"]
     *   // -> ["c", "a", "b"]
     *   // -> ["c", "b", "a"]
     *
     *   for (List perm : orderedPermutations(asList(1, 2, 2, 1))) {
     *     println(perm);
     *   }
     *   // -> [1, 1, 2, 2]
     *   // -> [1, 2, 1, 2]
     *   // -> [1, 2, 2, 1]
     *   // -> [2, 1, 1, 2]
     *   // -> [2, 1, 2, 1]
     *   // -> [2, 2, 1, 1]}
* *

Notes: This is an implementation of the algorithm for * Lexicographical Permutations Generation, described in Knuth's "The Art of * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The * iteration order follows the lexicographical order. This means that * the first permutation will be in ascending order, and the last will be in * descending order. * *

Elements that compare equal are considered equal and no new permutations * are created by swapping them. * *

An empty iterable has only one permutation, which is an empty list. * * @param elements the original iterable whose elements have to be permuted. * @param comparator a comparator for the iterable's elements. * @return an immutable {@link Collection} containing all the different * permutations of the original iterable. * @throws NullPointerException If the specified iterable is null, has any * null elements, or if the specified comparator is null. * @since 12.0 */ public static Collection> orderedPermutations(Collection elements, Comparator comparator) { return new OrderedPermutationCollection(elements, comparator); } private static final class OrderedPermutationCollection extends AbstractCollection> { final List inputList; final Comparator comparator; final int size; OrderedPermutationCollection(Collection input, Comparator comparator) { this.inputList = new ArrayList(input); N.sort(inputList, comparator); this.comparator = comparator; this.size = calculateSize(inputList, comparator); } @Override public int size() { return size; } @Override public boolean isEmpty() { return false; } @Override public Iterator> iterator() { return PermutationIterator.ordered(inputList, comparator); } @Override public boolean contains(Object obj) { if (obj instanceof Collection) { return isPermutations(inputList, (Collection) obj); } return false; } @Override public String toString() { return "orderedPermutationCollection(" + inputList + ")"; } /** * The number of permutations with repeated elements is calculated as * follows: *

    *
  • For an empty list, it is 1 (base case).
  • *
  • When r numbers are added to a list of n-r elements, the number of * permutations is increased by a factor of (n choose r).
  • *
*/ private static int calculateSize(List sortedInputList, Comparator comparator) { long permutations = 1; int n = 1; int r = 1; while (n < sortedInputList.size()) { int comparison = comparator.compare(sortedInputList.get(n - 1), sortedInputList.get(n)); if (comparison < 0) { // We move to the next non-repeated element. permutations *= Maths.binomial(n, r); r = 0; if (!isPositiveInt(permutations)) { return Integer.MAX_VALUE; } } n++; r++; } permutations *= Maths.binomial(n, r); if (!isPositiveInt(permutations)) { return Integer.MAX_VALUE; } return (int) permutations; } private static boolean isPositiveInt(long n) { return n >= 0 && n <= Integer.MAX_VALUE; } } /** * Returns {@code true} if the second list is a permutation of the first. */ private static boolean isPermutations(Collection a, Collection b) { if (a.size() != b.size()) { return false; } return N.difference(a, b).size() == 0; } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns every possible list that can be formed by choosing one element * from each of the given lists in order; the "n-ary * Cartesian * product" of the lists. For example:
   {@code
     *
     *   Lists.cartesianProduct(ImmutableList.of(
     *       ImmutableList.of(1, 2),
     *       ImmutableList.of("A", "B", "C")))}
* *

returns a list containing six lists in the following order: * *

    *
  • {@code ImmutableList.of(1, "A")} *
  • {@code ImmutableList.of(1, "B")} *
  • {@code ImmutableList.of(1, "C")} *
  • {@code ImmutableList.of(2, "A")} *
  • {@code ImmutableList.of(2, "B")} *
  • {@code ImmutableList.of(2, "C")} *
* *

The result is guaranteed to be in the "traditional", lexicographical * order for Cartesian products that you would get from nesting for loops: *

   {@code
     *
     *   for (B b0 : lists.get(0)) {
     *     for (B b1 : lists.get(1)) {
     *       ...
     *       ImmutableList tuple = ImmutableList.of(b0, b1, ...);
     *       // operate on tuple
     *     }
     *   }}
* *

Note that if any input list is empty, the Cartesian product will also be * empty. If no lists at all are provided (an empty list), the resulting * Cartesian product has one element, an empty list (counter-intuitive, but * mathematically consistent). * *

Performance notes: while the cartesian product of lists of size * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory * consumption is much smaller. When the cartesian product is constructed, the * input lists are merely copied. Only as the resulting list is iterated are * the individual lists created, and these are not retained after iteration. * * @param cs the lists to choose elements from, in the order that * the elements chosen from those lists should appear in the resulting * lists * @param any common base class shared by all axes (often just {@link * Object}) * @return the Cartesian product, as an immutable list containing immutable * lists * @throws IllegalArgumentException if the size of the cartesian product would * be greater than {@link Integer#MAX_VALUE} * @throws NullPointerException if {@code lists}, any one of the * {@code lists}, or any element of a provided list is null * @since 19.0 */ @SafeVarargs public static List> cartesianProduct(final Collection... cs) { if (N.isNullOrEmpty(cs)) { return new ArrayList<>(); } return cartesianProduct(Arrays.asList(cs)); } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns every possible list that can be formed by choosing one element * from each of the given lists in order; the "n-ary * Cartesian * product" of the lists. For example:

   {@code
     *
     *   Lists.cartesianProduct(ImmutableList.of(
     *       ImmutableList.of(1, 2),
     *       ImmutableList.of("A", "B", "C")))}
* *

returns a list containing six lists in the following order: * *

    *
  • {@code ImmutableList.of(1, "A")} *
  • {@code ImmutableList.of(1, "B")} *
  • {@code ImmutableList.of(1, "C")} *
  • {@code ImmutableList.of(2, "A")} *
  • {@code ImmutableList.of(2, "B")} *
  • {@code ImmutableList.of(2, "C")} *
* *

The result is guaranteed to be in the "traditional", lexicographical * order for Cartesian products that you would get from nesting for loops: *

   {@code
     *
     *   for (B b0 : lists.get(0)) {
     *     for (B b1 : lists.get(1)) {
     *       ...
     *       ImmutableList tuple = ImmutableList.of(b0, b1, ...);
     *       // operate on tuple
     *     }
     *   }}
* *

Note that if any input list is empty, the Cartesian product will also be * empty. If no lists at all are provided (an empty list), the resulting * Cartesian product has one element, an empty list (counter-intuitive, but * mathematically consistent). * *

Performance notes: while the power set of a set with size {@code * n} is of size {@code 2^n}, its memory usage is only {@code O(n)}. When the * power set is constructed, the input set is merely copied. Only as the * power set is iterated are the individual subsets created, and these subsets * themselves occupy only a small constant amount of memory. * * @param set the set of elements to construct a power set from * @return the power set, as an immutable set of immutable sets * @throws IllegalArgumentException if {@code set} has more than 30 unique * elements (causing the power set size to exceed the {@code int} range) * @throws NullPointerException if {@code set} is or contains {@code null} * @see Power set article at * Wikipedia * @since 4.0 */ public static Set> powerSet(Set set) { return new PowerSet<>(set); } private static final class PowerSet extends AbstractSet> { final ImmutableMap inputSet; PowerSet(Set input) { this.inputSet = indexMap(input); N.checkArgument(inputSet.size() <= 30, "Too many elements to create power set: %s > 30", inputSet.size()); } @Override public int size() { return 1 << inputSet.size(); } @Override public boolean isEmpty() { return false; } @Override public Iterator> iterator() { return new Iterator>() { private final int size = size(); private int position; @Override public boolean hasNext() { return position < size; } @Override public Set next() { if (!hasNext()) { throw new NoSuchElementException(); } return new SubSet<>(inputSet, position++); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public boolean contains(Object obj) { if (obj instanceof Set) { Set set = (Set) obj; return inputSet.keySet().containsAll(set); } return false; } @Override public boolean equals(Object obj) { if (obj instanceof PowerSet) { PowerSet that = (PowerSet) obj; return inputSet.equals(that.inputSet); } return super.equals(obj); } @Override public int hashCode() { /* * The sum of the sums of the hash codes in each subset is just the sum of * each input element's hash code times the number of sets that element * appears in. Each element appears in exactly half of the 2^n sets, so: */ return inputSet.keySet().hashCode() << (inputSet.size() - 1); } @Override public String toString() { return "powerSet(" + inputSet + ")"; } /** * Returns a map from the ith element of list to i. */ private static ImmutableMap indexMap(Collection c) { final Map map = new LinkedHashMap<>(); int i = 0; for (E e : c) { map.put(e, i++); } return ImmutableMap.of(map); } } private static final class SubSet extends AbstractSet { private final ImmutableMap inputSet; private final ImmutableList elements; private final int mask; SubSet(ImmutableMap inputSet, int mask) { this.inputSet = inputSet; this.elements = ImmutableList.of((E[]) inputSet.keySet().toArray()); this.mask = mask; } @Override public Iterator iterator() { return new Iterator() { int remainingSetBits = mask; @Override public boolean hasNext() { return remainingSetBits != 0; } @Override public E next() { int index = Integer.numberOfTrailingZeros(remainingSetBits); if (index == 32) { throw new NoSuchElementException(); } remainingSetBits &= ~(1 << index); return elements.get(index); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public int size() { return Integer.bitCount(mask); } @Override public boolean contains(Object o) { Integer index = inputSet.get(o); return index != null && (mask & (1 << index)) != 0; } } /** * Note: copy from Google Guava under Apache License v2. *
* * Returns a {@link Collection} of all the permutations of the specified * {@link Collection}. * *

Performance notes: while the cartesian product of lists of size * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory * consumption is much smaller. When the cartesian product is constructed, the * input lists are merely copied. Only as the resulting list is iterated are * the individual lists created, and these are not retained after iteration. * * @param cs the lists to choose elements from, in the order that * the elements chosen from those lists should appear in the resulting * lists * @param any common base class shared by all axes (often just {@link * Object}) * @return the Cartesian product, as an immutable list containing immutable * lists * @throws IllegalArgumentException if the size of the cartesian product would * be greater than {@link Integer#MAX_VALUE} * @throws NullPointerException if {@code lists}, any one of the {@code lists}, * or any element of a provided list is null * @since 19.0 */ public static List> cartesianProduct(final Collection> cs) { return new CartesianList<>(cs); } private static final class CartesianList extends AbstractList> implements RandomAccess { private final transient Object[][] axes; private final transient int[] axesSizeProduct; CartesianList(final Collection> cs) { final Iterator> iter = cs.iterator(); this.axes = new Object[cs.size()][]; for (int i = 0, len = this.axes.length; i < len; i++) { this.axes[i] = iter.next().toArray(); } this.axesSizeProduct = new int[axes.length + 1]; axesSizeProduct[axes.length] = 1; try { for (int i = axes.length - 1; i >= 0; i--) { axesSizeProduct[i] = Maths.multiplyExact(axesSizeProduct[i + 1], axes[i].length); } } catch (ArithmeticException e) { throw new IllegalArgumentException("Cartesian product too large; must have size at most Integer.MAX_VALUE"); } } @Override public List get(final int index) { N.checkArgument(index < size(), "Invalid index %s. It must be less than the size %s", index, size()); final List result = new ArrayList<>(axes.length); for (int k = 0, len = axes.length; k < len; k++) { result.add((E) axes[k][getAxisIndexForProductIndex(index, k)]); } return result; } @Override public int size() { return axesSizeProduct[0]; } @Override public boolean contains(Object obj) { if (!(obj instanceof Collection)) { return false; } final Collection c = (Collection) obj; if (c.size() != axes.length) { return false; } int idx = 0; for (Object e : c) { boolean found = false; for (Object p : axes[idx++]) { if (N.equals(e, p)) { found = true; break; } } if (found == false) { return false; } } return true; } private int getAxisIndexForProductIndex(int index, int axis) { return (index / axesSizeProduct[axis + 1]) % axes[axis].length; } } }