Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.util.Iterables Maven / Gradle / Ivy
/*
* Copyright (c) 2018, 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.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
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.RandomAccess;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.u.Holder;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.stream.Stream;
/**
* It's an extension and wrapper for Google Guava.
*
* @since 1.2.7
*
* @author Haiyang Li
*/
public final class Iterables {
private static final Logger logger = LoggerFactory.getLogger(Iterables.class);
private Iterables() {
// singleton.
}
/**
*
* @param a
* @param b
* @return
*/
public static Set differentSet(final Collection extends T> a, final Collection> b) {
if (N.isNullOrEmpty(a)) {
return new HashSet<>();
} else if (N.isNullOrEmpty(b)) {
return new HashSet<>(a);
}
final Set result = new HashSet<>(a);
Iterables.removeAll(a, b);
return result;
}
/**
*
* @param a
* @param b
* @return
*/
public static Set symmetricDifferentSet(final Collection extends T> a, final Collection extends T> b) {
if (N.isNullOrEmpty(a)) {
return N.isNullOrEmpty(b) ? new HashSet() : new HashSet<>(b);
} else if (N.isNullOrEmpty(b)) {
return N.isNullOrEmpty(a) ? new HashSet() : new HashSet<>(a);
}
final Set commonSet = Iterables.commonSet(a, b);
final Set result = new HashSet<>(a);
for (T e : a) {
if (!commonSet.contains(e)) {
result.add(e);
}
}
for (T e : b) {
if (!commonSet.contains(e)) {
result.add(e);
}
}
return result;
}
/**
*
* @param a
* @param b
* @return
*/
public static Set commonSet(final Collection extends T> a, final Collection> b) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return new HashSet<>();
}
return commonSet(N.asList(a, (Collection extends T>) b));
}
public static Set commonSet(final Collection extends Collection extends T>> c) {
if (N.isNullOrEmpty(c)) {
return new HashSet<>();
} else if (c.size() == 1) {
return N.newHashSet(c.iterator().next());
}
Collection extends T> smallest = null;
for (Collection extends T> e : c) {
if (N.isNullOrEmpty(e)) {
return new HashSet<>();
}
if (smallest == null || e.size() < smallest.size()) {
smallest = e;
}
}
final Map map = new HashMap<>();
for (T e : smallest) {
map.put(e, new MutableInt(1));
}
int cnt = 1;
MutableInt val = null;
for (Collection extends T> ec : c) {
if (ec == smallest) {
continue;
}
for (T e : ec) {
val = map.get(e);
if (val == null) {
// do nothing.
} else if (val.intValue() < cnt) {
// map.remove(e);
} else if (val.intValue() == cnt) {
val.increment();
}
}
cnt++;
}
final Set result = new HashSet<>(map.size());
for (Map.Entry entry : map.entrySet()) {
if (entry.getValue().intValue() == cnt) {
result.add(entry.getKey());
}
}
return result;
}
public static boolean removeAll(Collection> c, Collection> objsToRemove) {
if (N.isNullOrEmpty(c) || N.isNullOrEmpty(objsToRemove)) {
return false;
}
if (c instanceof HashSet && !(objsToRemove instanceof Set)) {
boolean result = false;
for (Object e : objsToRemove) {
result |= c.remove(e);
if (c.size() == 0) {
break;
}
}
return result;
} else {
return c.removeAll(objsToRemove);
}
}
public static boolean retainAll(Collection> c, Collection> objsToKeep) {
if (N.isNullOrEmpty(c)) {
return false;
} else if (N.isNullOrEmpty(objsToKeep)) {
c.clear();
return true;
}
if (c instanceof HashSet && !(objsToKeep instanceof Set) && (c.size() > 9 || objsToKeep.size() > 9)) {
return c.retainAll(new HashSet<>(objsToKeep));
} else {
return c.retainAll(objsToKeep);
}
}
/**
*
* @param iterable
* @return
* throws DuplicatedResultException if there are more than one elements in the specified {@code iterable}.
*/
public static Nullable getOnlyElement(Iterable extends T> iterable) {
if (iterable == null) {
return Nullable.empty();
}
return Iterators.getOnlyElement(iterable.iterator());
}
/**
*
* @param c
* @param objToFind
* @return
*/
public static OptionalInt indexOf(final Collection> c, final Object objToFind) {
if (N.isNullOrEmpty(c)) {
return OptionalInt.empty();
}
int idx = 0;
for (Object e : c) {
if (N.equals(e, objToFind)) {
return OptionalInt.of(idx);
}
idx++;
}
return OptionalInt.empty();
}
/**
*
* @param c
* @param objToFind
* @return
*/
public static OptionalInt lastIndexOf(final Collection> c, final Object objToFind) {
if (N.isNullOrEmpty(c)) {
return OptionalInt.empty();
}
final int size = c.size();
if (c instanceof List) {
final List list = (List) c;
if (c instanceof RandomAccess) {
for (int i = size - 1; i >= 0; i--) {
if (N.equals(list.get(i), objToFind)) {
return OptionalInt.of(i);
}
}
} else {
final ListIterator iter = list.listIterator(list.size());
for (int i = size - 1; iter.hasPrevious(); i--) {
if (N.equals(iter.previous(), objToFind)) {
return OptionalInt.of(i);
}
}
}
return OptionalInt.empty();
} else if (c instanceof Deque) {
final Iterator iter = ((Deque) c).descendingIterator();
for (int i = size - 1; iter.hasNext(); i--) {
if (N.equals(iter.next(), objToFind)) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
} else {
final Object[] a = c.toArray();
for (int i = a.length - 1; i >= 0; i--) {
if (N.equals(a[i], objToFind)) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
}
public static OptionalInt findFirstIndex(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return OptionalInt.empty();
}
for (int len = a.length, i = 0; i < len; i++) {
if (predicate.test(a[i])) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
public static OptionalInt findFirstIndex(final Collection extends T> c, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(c)) {
return OptionalInt.empty();
}
int idx = 0;
for (T e : c) {
if (predicate.test(e)) {
return OptionalInt.of(idx);
}
idx++;
}
return OptionalInt.empty();
}
public static OptionalInt findLastIndex(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return OptionalInt.empty();
}
for (int len = a.length, i = len - 1; i >= 0; i--) {
if (predicate.test(a[i])) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
public static OptionalInt findLastIndex(final Collection extends T> c, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(c)) {
return OptionalInt.empty();
}
final int size = c.size();
if (c instanceof List) {
final List list = (List) c;
if (c 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 (c instanceof Deque) {
final Iterator iter = ((Deque) c).descendingIterator();
for (int i = size - 1; iter.hasNext(); i--) {
if (predicate.test(iter.next())) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
} else {
final T[] a = (T[]) c.toArray();
for (int i = a.length - 1; i >= 0; i--) {
if (predicate.test(a[i])) {
return OptionalInt.of(i);
}
}
return OptionalInt.empty();
}
}
public static Nullable findFirst(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return Nullable.empty();
}
for (int len = a.length, i = 0; i < len; i++) {
if (predicate.test(a[i])) {
return Nullable.of(a[i]);
}
}
return Nullable.empty();
}
public static Nullable findFirst(final Collection c, Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(c)) {
return Nullable.empty();
}
for (T e : c) {
if (predicate.test(e)) {
return Nullable.of(e);
}
}
return Nullable.empty();
}
public static Nullable findLast(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return Nullable.empty();
}
for (int len = a.length, i = len - 1; i >= 0; i--) {
if (predicate.test(a[i])) {
return Nullable.of(a[i]);
}
}
return Nullable.empty();
}
public static Nullable findLast(final Collection c, Try.Predicate super T, E> predicate) throws E {
return findLast(c, predicate, false);
}
public static Optional findFirstNonNull(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return Optional.empty();
}
for (int len = a.length, i = 0; i < len; i++) {
if (a[i] != null && predicate.test(a[i])) {
return Optional.of(a[i]);
}
}
return Optional.empty();
}
public static Optional findFirstNonNull(final Collection c, Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(c)) {
return Optional.empty();
}
for (T e : c) {
if (e != null && predicate.test(e)) {
return Optional.of(e);
}
}
return Optional.empty();
}
public static Optional findLastNonNull(final T[] a, final Try.Predicate super T, E> predicate) throws E {
if (N.isNullOrEmpty(a)) {
return Optional.empty();
}
for (int len = a.length, i = len - 1; i >= 0; i--) {
if (a[i] != null && predicate.test(a[i])) {
return Optional.of(a[i]);
}
}
return Optional.empty();
}
public static Optional findLastNonNull(final Collection c, Try.Predicate super T, E> predicate) throws E {
return findLast(c, predicate, true);
}
private static R findLast(final Collection c, Try.Predicate super T, E> predicate, boolean isForNonNull) throws E {
if (N.isNullOrEmpty(c)) {
return (R) (isForNonNull ? Optional.empty() : Nullable.empty());
}
T e = null;
if (c instanceof List) {
final List list = (List) c;
if (c instanceof RandomAccess) {
for (int i = c.size() - 1; i >= 0; i--) {
e = list.get(i);
if ((!isForNonNull || e != null) && predicate.test(e)) {
return (R) (isForNonNull ? Optional.of(e) : Nullable.of(e));
}
}
} else {
final ListIterator iter = list.listIterator(list.size());
while (iter.hasPrevious()) {
e = iter.previous();
if ((!isForNonNull || e != null) && predicate.test(e)) {
return (R) (isForNonNull ? Optional.of(e) : Nullable.of(e));
}
}
}
return (R) (isForNonNull ? Optional.empty() : Nullable.empty());
} else if (c instanceof Deque) {
final Iterator iter = ((Deque) c).descendingIterator();
while (iter.hasNext()) {
e = iter.next();
if ((!isForNonNull || e != null) && predicate.test(e)) {
return (R) (isForNonNull ? Optional.of(e) : Nullable.of(e));
}
}
return (R) (isForNonNull ? Optional.empty() : Nullable.empty());
} else {
final T[] a = (T[]) c.toArray();
for (int i = a.length - 1; i >= 0; i--) {
if ((!isForNonNull || a[i] != null) && predicate.test(a[i])) {
return (R) (isForNonNull ? Optional.of(a[i]) : Nullable.of(a[i]));
}
}
return (R) (isForNonNull ? Optional.empty() : Nullable.empty());
}
}
public static List> rollup(Collection extends T> 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.
*
*
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
*/
public static Set> powerSet(Set set) {
return new PowerSet<>(set);
}
/**
* Note: copy from Google Guava under Apache License v2.
*
*
* Returns a {@link Collection} of all the permutations of the specified
* {@link Collection}.
*
* 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.
*/
public static Collection> permutations(Collection elements) {
return new PermutationCollection(elements);
}
/**
* 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.
*/
public static > Collection> orderedPermutations(Collection elements) {
return orderedPermutations(elements, Comparators.naturalOrder());
}
/**
* 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.
*/
public static Collection> orderedPermutations(Collection elements, Comparator super E> comparator) {
return new OrderedPermutationCollection(elements, comparator);
}
/**
* 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
*/
@SafeVarargs
public static List> cartesianProduct(final Collection extends E>... cs) {
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 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
*/
public static List> cartesianProduct(final Collection extends Collection extends E>> cs) {
return new CartesianList<>(cs);
}
/**
* 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;
}
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;
}
}
private static final class PermutationCollection extends AbstractCollection> {
final List inputList;
PermutationCollection(Collection input) {
this.inputList = new ArrayList<>(input);
}
@Override
public int size() {
return Matth.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 + ")";
}
}
private static final class OrderedPermutationCollection extends AbstractCollection> {
final List inputList;
final Comparator super E> comparator;
final int size;
OrderedPermutationCollection(Collection input, Comparator super E> 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 super E> 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 *= Matth.binomial(n, r);
r = 0;
if (!isPositiveInt(permutations)) {
return Integer.MAX_VALUE;
}
}
n++;
r++;
}
permutations *= Matth.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;
}
}
private static final class CartesianList extends AbstractList> implements RandomAccess {
private final transient Object[][] axes;
private final transient int[] axesSizeProduct;
CartesianList(final Collection extends Collection extends E>> cs) {
final Iterator extends Collection extends E>> 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] = Matth.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;
}
}
public static void parse(final Iterator extends T> iter, final Try.Consumer super T, E> elementParser) throws E {
parse(iter, elementParser, Fn.emptyAction());
}
public static void parse(final Iterator extends T> iter, final Try.Consumer super T, E> elementParser,
final Try.Runnable onComplete) throws E, E2 {
parse(iter, 0, Long.MAX_VALUE, elementParser, onComplete);
}
public static void parse(final Iterator extends T> iter, final long offset, final long count,
final Try.Consumer super T, E> elementParser) throws E {
parse(iter, offset, count, elementParser, Fn.emptyAction());
}
public static void parse(final Iterator extends T> iter, final long offset, final long count,
final Try.Consumer super T, E> elementParser, final Try.Runnable onComplete) throws E, E2 {
parse(iter, offset, count, 0, 0, elementParser, onComplete);
}
public static void parse(final Iterator extends T> iter, long offset, long count, final int processThreadNum,
final int queueSize, final Try.Consumer super T, E> elementParser) throws E {
parse(iter, offset, count, processThreadNum, queueSize, elementParser, Fn.emptyAction());
}
/**
* Parse the elements in the specified iterators one by one.
*
* @param iter
* @param offset
* @param count
* @param processThreadNum new threads started to parse/process the lines/records
* @param queueSize size of queue to save the processing records/lines loaded from source data. Default size is 1024.
* @param elementParser.
* @param onComplete
* @param onError
*/
public static void parse(final Iterator extends T> iter, long offset, long count,
final int processThreadNum, final int queueSize, final Try.Consumer super T, E> elementParser, final Try.Runnable onComplete) throws E, E2 {
parse(N.asList(iter), offset, count, 0, processThreadNum, queueSize, elementParser, onComplete);
}
public static void parse(final Collection extends Iterator extends T>> iterators,
final Try.Consumer super T, E> elementParser) throws E {
parse(iterators, elementParser, Fn.emptyAction());
}
public static void parse(final Collection extends Iterator extends T>> iterators,
final Try.Consumer super T, E> elementParser, final Try.Runnable onComplete) throws E, E2 {
parse(iterators, 0, Long.MAX_VALUE, elementParser, onComplete);
}
public static void parse(final Collection extends Iterator extends T>> iterators, final long offset, final long count,
final Try.Consumer super T, E> elementParser) throws E {
parse(iterators, offset, count, elementParser, Fn.emptyAction());
}
public static void parse(final Collection extends Iterator extends T>> iterators, final long offset,
final long count, final Try.Consumer super T, E> elementParser, final Try.Runnable onComplete) throws E, E2 {
parse(iterators, offset, count, 0, 0, 0, elementParser, onComplete);
}
public static void parse(final Collection extends Iterator extends T>> iterators, final int readThreadNum,
final int processThreadNum, final int queueSize, final Try.Consumer super T, E> elementParser) throws E {
parse(iterators, readThreadNum, processThreadNum, queueSize, elementParser, Fn.emptyAction());
}
public static void parse(final Collection extends Iterator extends T>> iterators,
final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer super T, E> elementParser,
final Try.Runnable onComplete) throws E {
parse(iterators, 0, Long.MAX_VALUE, readThreadNum, processThreadNum, queueSize, elementParser);
}
public static void parse(final Collection extends Iterator extends T>> iterators, final long offset, final long count,
final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer super T, E> elementParser) throws E {
parse(iterators, offset, count, readThreadNum, processThreadNum, queueSize, elementParser, Fn.emptyAction());
}
/**
* Parse the elements in the specified iterators one by one.
*
* @param iterators
* @param offset
* @param count
* @param readThreadNum new threads started to parse/process the lines/records
* @param processThreadNum new threads started to parse/process the lines/records
* @param queueSize size of queue to save the processing records/lines loaded from source data. Default size is 1024.
* @param elementParser.
* @param onComplete
*/
public static void parse(final Collection extends Iterator extends T>> iterators, final long offset,
final long count, final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer super T, E> elementParser,
final Try.Runnable onComplete) throws E, E2 {
N.checkArgument(offset >= 0 && count >= 0, "'offset'=%s and 'count'=%s can not be negative", offset, count);
if (N.isNullOrEmpty(iterators)) {
return;
}
if (logger.isInfoEnabled()) {
logger.info("### Start to parse");
}
try (final Stream stream = ((readThreadNum > 0 || queueSize > 0)
? Stream.parallelConcatt(iterators, (readThreadNum == 0 ? 1 : readThreadNum), (queueSize == 0 ? 1024 : queueSize))
: Stream.concatt(iterators))) {
final Iterator extends T> iteratorII = stream.skip(offset).limit(count).iterator();
if (processThreadNum == 0) {
while (iteratorII.hasNext()) {
elementParser.accept(iteratorII.next());
}
if (onComplete != null) {
onComplete.run();
}
} else {
final AtomicInteger activeThreadNum = new AtomicInteger();
final ExecutorService executorService = Executors.newFixedThreadPool(processThreadNum);
final Holder errorHolder = new Holder<>();
for (int i = 0; i < processThreadNum; i++) {
activeThreadNum.incrementAndGet();
executorService.execute(new Runnable() {
@Override
public void run() {
T element = null;
try {
while (errorHolder.value() == null) {
synchronized (iteratorII) {
if (iteratorII.hasNext()) {
element = iteratorII.next();
} else {
break;
}
}
elementParser.accept(element);
}
} catch (Exception e) {
synchronized (errorHolder) {
if (errorHolder.value() == null) {
errorHolder.setValue(e);
} else {
errorHolder.value().addSuppressed(e);
}
}
} finally {
activeThreadNum.decrementAndGet();
}
}
});
}
while (activeThreadNum.get() > 0) {
N.sleep(1);
}
if (errorHolder.value() == null && onComplete != null) {
try {
onComplete.run();
} catch (Exception e) {
errorHolder.setValue(e);
}
}
if (errorHolder.value() != null) {
throw N.toRuntimeException(errorHolder.value());
}
}
} finally {
if (logger.isInfoEnabled()) {
logger.info("### End to parse");
}
}
}
}