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

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 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 a, final Collection 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 a, final Collection b) {
        if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
            return new HashSet<>();
        }

        return commonSet(N.asList(a, (Collection) b));
    }

    public static  Set commonSet(final Collection> c) {
        if (N.isNullOrEmpty(c)) {
            return new HashSet<>();
        } else if (c.size() == 1) {
            return N.newHashSet(c.iterator().next());
        }

        Collection smallest = null;

        for (Collection 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 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 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 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 c, final Try.Predicate 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 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 c, final Try.Predicate 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 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 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 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 predicate) throws E {
        return findLast(c, predicate, false);
    }

    public static  Optional findFirstNonNull(final T[] a, final Try.Predicate 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 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 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 predicate) throws E {
        return findLast(c, predicate, true);
    }

    private static  R findLast(final Collection c, Try.Predicate 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 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 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... 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> 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 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 *= 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> 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] = 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 iter, final Try.Consumer elementParser) throws E { parse(iter, elementParser, Fn.emptyAction()); } public static void parse(final Iterator iter, final Try.Consumer elementParser, final Try.Runnable onComplete) throws E, E2 { parse(iter, 0, Long.MAX_VALUE, elementParser, onComplete); } public static void parse(final Iterator iter, final long offset, final long count, final Try.Consumer elementParser) throws E { parse(iter, offset, count, elementParser, Fn.emptyAction()); } public static void parse(final Iterator iter, final long offset, final long count, final Try.Consumer elementParser, final Try.Runnable onComplete) throws E, E2 { parse(iter, offset, count, 0, 0, elementParser, onComplete); } public static void parse(final Iterator iter, long offset, long count, final int processThreadNum, final int queueSize, final Try.Consumer 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 iter, long offset, long count, final int processThreadNum, final int queueSize, final Try.Consumer 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> iterators, final Try.Consumer elementParser) throws E { parse(iterators, elementParser, Fn.emptyAction()); } public static void parse(final Collection> iterators, final Try.Consumer elementParser, final Try.Runnable onComplete) throws E, E2 { parse(iterators, 0, Long.MAX_VALUE, elementParser, onComplete); } public static void parse(final Collection> iterators, final long offset, final long count, final Try.Consumer elementParser) throws E { parse(iterators, offset, count, elementParser, Fn.emptyAction()); } public static void parse(final Collection> iterators, final long offset, final long count, final Try.Consumer elementParser, final Try.Runnable onComplete) throws E, E2 { parse(iterators, offset, count, 0, 0, 0, elementParser, onComplete); } public static void parse(final Collection> iterators, final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer elementParser) throws E { parse(iterators, readThreadNum, processThreadNum, queueSize, elementParser, Fn.emptyAction()); } public static void parse(final Collection> iterators, final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer elementParser, final Try.Runnable onComplete) throws E { parse(iterators, 0, Long.MAX_VALUE, readThreadNum, processThreadNum, queueSize, elementParser); } public static void parse(final Collection> iterators, final long offset, final long count, final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer 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> iterators, final long offset, final long count, final int readThreadNum, final int processThreadNum, final int queueSize, final Try.Consumer 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 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"); } } } }