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

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

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 2.1.12
Show newest version
/*
 * 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.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

import com.landawn.abacus.util.Tuple.Tuple2;
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.function.Function;

// TODO: Auto-generated Javadoc
/**
 * The methods in this class should only read the input {@code Collections/Arrays}, not modify any of them.
 *
 * @author Haiyang Li
 * @since 1.2.7
 */
public final class Iterables {
    /**
     * Instantiates a new Iterables.
     */
    private Iterables() {
        // singleton.
    }

    /**
     *
     * @param 
     * @param iterable
     * @return
     */
    public static  Iterator iterator(Iterable iterable) {
        return iterable == null ? ObjIterator. empty() : iterable.iterator();
    }

    /**
     * Min.
     *
     * @param  the generic type
     * @param c the c
     * @return the nullable
     */
    public static > Nullable min(final Collection c) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.min(c));
    }

    /**
     * Min.
     *
     * @param  the generic type
     * @param a the a
     * @return the nullable
     */
    public static > Nullable min(final T[] a) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.min(a));
    }

    /**
     * Min.
     *
     * @param  the generic type
     * @param c the c
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable min(final Collection c, final Comparator cmp) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.min(c, cmp));
    }

    /**
     * Min.
     *
     * @param  the generic type
     * @param a the a
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable min(final T[] a, final Comparator cmp) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.min(a, cmp));
    }

    /**
     * Min by.
     *
     * @param  the generic type
     * @param c the c
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable minBy(final Collection c, final Function keyMapper) {
        return min(c, Fn.comparingBy(keyMapper));
    }

    /**
     * Min by.
     *
     * @param  the generic type
     * @param a the a
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable minBy(final T[] a, final Function keyMapper) {
        return min(a, Fn.comparingBy(keyMapper));
    }

    /**
     * Max.
     *
     * @param  the generic type
     * @param c the c
     * @return the nullable
     */
    public static > Nullable max(final Collection c) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.max(c));
    }

    /**
     * Max.
     *
     * @param  the generic type
     * @param a the a
     * @return the nullable
     */
    public static > Nullable max(final T[] a) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.max(a));
    }

    /**
     * Max.
     *
     * @param  the generic type
     * @param c the c
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable max(final Collection c, final Comparator cmp) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.max(c, cmp));
    }

    /**
     * Max.
     *
     * @param  the generic type
     * @param a the a
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable max(final T[] a, final Comparator cmp) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.max(a, cmp));
    }

    /**
     * Max by.
     *
     * @param  the generic type
     * @param c the c
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable maxBy(final Collection c, final Function keyMapper) {
        return max(c, Fn.comparingBy(keyMapper));
    }

    /**
     * Max by.
     *
     * @param  the generic type
     * @param a the a
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable maxBy(final T[] a, final Function keyMapper) {
        return max(a, Fn.comparingBy(keyMapper));
    }

    /**
     * Median.
     *
     * @param  the generic type
     * @param c the c
     * @return the nullable
     */
    public static > Nullable median(final Collection c) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.median(c));
    }

    /**
     * Median.
     *
     * @param  the generic type
     * @param a the a
     * @return the nullable
     */
    public static > Nullable median(final T[] a) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.median(a));
    }

    /**
     * Median.
     *
     * @param  the generic type
     * @param c the c
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable median(final Collection c, final Comparator cmp) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.median(c, cmp));
    }

    /**
     * Median.
     *
     * @param  the generic type
     * @param a the a
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable median(final T[] a, final Comparator cmp) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.median(a, cmp));
    }

    /**
     * Median by.
     *
     * @param  the generic type
     * @param c the c
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable medianBy(final Collection c, final Function keyMapper) {
        return median(c, Fn.comparingBy(keyMapper));
    }

    /**
     * Median by.
     *
     * @param  the generic type
     * @param a the a
     * @param keyMapper the key mapper
     * @return the nullable
     */
    @SuppressWarnings("rawtypes")
    public static  Nullable medianBy(final T[] a, final Function keyMapper) {
        return median(a, Fn.comparingBy(keyMapper));
    }

    /**
     * Kth largest.
     *
     * @param  the generic type
     * @param c the c
     * @param k the k
     * @return the nullable
     */
    public static > Nullable kthLargest(final Collection c, final int k) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.kthLargest(c, k));
    }

    /**
     * Kth largest.
     *
     * @param  the generic type
     * @param a the a
     * @param k the k
     * @return the nullable
     */
    public static > Nullable kthLargest(final T[] a, final int k) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.kthLargest(a, k));
    }

    /**
     * Kth largest.
     *
     * @param  the generic type
     * @param c the c
     * @param k the k
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable kthLargest(final Collection c, final int k, final Comparator cmp) {
        return N.isNullOrEmpty(c) ? Nullable. empty() : Nullable.of(N.kthLargest(c, k, cmp));
    }

    /**
     * Kth largest.
     *
     * @param  the generic type
     * @param a the a
     * @param k the k
     * @param cmp the cmp
     * @return the nullable
     */
    public static  Nullable kthLargest(final T[] a, final int k, final Comparator cmp) {
        return N.isNullOrEmpty(a) ? Nullable. empty() : Nullable.of(N.kthLargest(a, k, cmp));
    }

    /**
     * Index of.
     *
     * @param c the c
     * @param objToFind the obj to find
     * @return the optional int
     */
    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();
    }

    /**
     * Index of.
     *
     * @param a the a
     * @param objToFind the obj to find
     * @return the optional int
     */
    public static OptionalInt indexOf(final Object[] a, final Object objToFind) {
        if (N.isNullOrEmpty(a)) {
            return OptionalInt.empty();
        }

        for (int i = 0, len = a.length; i < len; i++) {
            if (N.equals(a[i], objToFind)) {
                return OptionalInt.of(i);
            }
        }

        return OptionalInt.empty();
    }

    /**
     * Last index of.
     *
     * @param c the c
     * @param objToFind the obj to find
     * @return the optional int
     */
    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();
        }
    }

    /**
     * Last index of.
     *
     * @param a the a
     * @param objToFind the obj to find
     * @return the optional int
     */
    public static OptionalInt lastIndexOf(final Object[] a, final Object objToFind) {
        if (N.isNullOrEmpty(a)) {
            return OptionalInt.empty();
        }

        for (int i = a.length - 1; i >= 0; i--) {
            if (N.equals(a[i], objToFind)) {
                return OptionalInt.of(i);
            }
        }

        return OptionalInt.empty();
    }

    /**
     * Find first index.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the optional int
     * @throws E the e
     * @deprecated replace by N.findFirstIndex
     * @see N#findFirstIndex(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  OptionalInt findFirstIndex(final T[] a, final Throwables.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();
    }

    /**
     * Find first index.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the optional int
     * @throws E the e
     * @deprecated replace by N.findFirstIndex
     * @see N#findFirstIndex(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  OptionalInt findFirstIndex(final Collection c, final Throwables.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();
    }

    /**
     * Find last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the optional int
     * @throws E the e
     * @deprecated replace by N.findLastIndex
     * @see N#findLastIndex(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  OptionalInt findLastIndex(final T[] a, final Throwables.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();
    }

    /**
     * Find last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the optional int
     * @throws E the e
     * @deprecated replace by N.findLastIndex
     * @see N#findLastIndex(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  OptionalInt findLastIndex(final Collection c, final Throwables.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();
        }
    }

    /**
     * Find first or last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param c the c
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the optional int
     * @throws E the e
     * @throws E2 the e2
     */
    public static  OptionalInt findFirstOrLastIndex(final Collection c,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(c)) {
            return OptionalInt.empty();
        }

        final OptionalInt res = findFirstIndex(c, predicateForFirst);

        return res.isPresent() ? res : findLastIndex(c, predicateForLast);
    }

    /**
     * Find first or last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the optional int
     * @throws E the e
     * @throws E2 the e2
     */
    public static  OptionalInt findFirstOrLastIndex(final T[] a,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(a)) {
            return OptionalInt.empty();
        }

        final OptionalInt res = findFirstIndex(a, predicateForFirst);

        return res.isPresent() ? res : findLastIndex(a, predicateForLast);
    }

    /**
     * Find first and last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the pair
     * @throws E the e
     */
    public static  Pair findFirstAndLastIndex(final Collection c,
            final Throwables.Predicate predicate) throws E {
        return findFirstAndLastIndex(c, predicate, predicate);
    }

    /**
     * Find first and last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param c the c
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the pair
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Pair findFirstAndLastIndex(final Collection c,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(c)) {
            return Pair.of(OptionalInt.empty(), OptionalInt.empty());
        }

        return Pair.of(findFirstIndex(c, predicateForFirst), findLastIndex(c, predicateForLast));
    }

    /**
     * Find first and last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the pair
     * @throws E the e
     */
    public static  Pair findFirstAndLastIndex(final T[] a, final Throwables.Predicate predicate)
            throws E {
        return findFirstAndLastIndex(a, predicate, predicate);
    }

    /**
     * Find first and last index.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the pair
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Pair findFirstAndLastIndex(final T[] a,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(a)) {
            return Pair.of(OptionalInt.empty(), OptionalInt.empty());
        }

        return Pair.of(findFirstIndex(a, predicateForFirst), findLastIndex(a, predicateForLast));
    }

    /**
     * Find first.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the nullable
     * @throws E the e
     * @deprecated replace by N.findFirst
     * @see N#findFirst(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Nullable findFirst(final T[] a, final Throwables.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();
    }

    /**
     * Find first.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the nullable
     * @throws E the e
     * @deprecated replace by N.findFirst
     * @see N#findFirst(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Nullable findFirst(final Collection c, Throwables.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();
    }

    /**
     * Find last.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the nullable
     * @throws E the e
     * @deprecated replace by N.findLast
     * @see N#findLast(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Nullable findLast(final T[] a, final Throwables.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();
    }

    /**
     * Find last.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the nullable
     * @throws E the e
     * @deprecated replace by N.findLast
     * @see N#findLast(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Nullable findLast(final Collection c, Throwables.Predicate predicate) throws E {
        return findLast(c, predicate, false);
    }

    /**
     * Find first non null.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the optional
     * @throws E the e
     * @deprecated replace by N.findFirstNonNull
     * @see N#findFirstNonNull(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Optional findFirstNonNull(final T[] a, final Throwables.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();
    }

    /**
     * Find first non null.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the optional
     * @throws E the e
     * @deprecated replace by N.findFirstNonNull
     * @see N#findFirstNonNull(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Optional findFirstNonNull(final Collection c, Throwables.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();
    }

    /**
     * Find last non null.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the optional
     * @throws E the e
     * @deprecated replace by N.findLastNonNull
     * @see N#findLastNonNull(Object[], com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Optional findLastNonNull(final T[] a, final Throwables.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();
    }

    /**
     * Find last non null.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the optional
     * @throws E the e
     * @deprecated replace by N.findLastNonNull
     * @see N#findLastNonNull(Collection, com.landawn.abacus.util.Throwables.Predicate)
     */
    @Deprecated
    public static  Optional findLastNonNull(final Collection c, Throwables.Predicate predicate) throws E {
        return findLast(c, predicate, true);
    }

    /**
     * Find last.
     *
     * @param  the generic type
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @param isForNonNull the is for non null
     * @return the r
     * @throws E the e
     */
    private static  R findLast(final Collection c, Throwables.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());
        }
    }

    /**
     * Find first or last.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param c the c
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the nullable
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Nullable findFirstOrLast(final Collection c,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(c)) {
            return Nullable. empty();
        }

        final Nullable res = findFirst(c, predicateForFirst);

        return res.isPresent() ? res : findLast(c, predicateForLast);
    }

    /**
     * Find first or last.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the nullable
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Nullable findFirstOrLast(final T[] a,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(a)) {
            return Nullable. empty();
        }

        final Nullable res = findFirst(a, predicateForFirst);

        return res.isPresent() ? res : findLast(a, predicateForLast);
    }

    /**
     * Find first and last.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param predicate the predicate
     * @return the pair
     * @throws E the e
     */
    public static  Pair, Nullable> findFirstAndLast(final Collection c,
            final Throwables.Predicate predicate) throws E {
        return findFirstAndLast(c, predicate, predicate);
    }

    /**
     * Find first and last.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param c the c
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the pair
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Pair, Nullable> findFirstAndLast(final Collection c,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(c)) {
            return Pair.of(Nullable. empty(), Nullable. empty());
        }

        return Pair.of(findFirst(c, predicateForFirst), findLast(c, predicateForLast));
    }

    /**
     * Find first and last.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param predicate the predicate
     * @return the pair
     * @throws E the e
     */
    public static  Pair, Nullable> findFirstAndLast(final T[] a, final Throwables.Predicate predicate)
            throws E {
        return findFirstAndLast(a, predicate, predicate);
    }

    /**
     * Find first and last.
     *
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param predicateForFirst the predicate for first
     * @param predicateForLast the predicate for last
     * @return the pair
     * @throws E the e
     * @throws E2 the e2
     */
    public static  Pair, Nullable> findFirstAndLast(final T[] a,
            final Throwables.Predicate predicateForFirst, final Throwables.Predicate predicateForLast) throws E, E2 {
        if (N.isNullOrEmpty(a)) {
            return Pair.of(Nullable. empty(), Nullable. empty());
        }

        return Pair.of(findFirst(a, predicateForFirst), findLast(a, predicateForLast));
    }

    /**
     * All match.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#allMatch(Collection, com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean allMatch(final Collection c, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(c)) {
            return true;
        }

        for (T e : c) {
            if (filter.test(e) == false) {
                return false;
            }
        }

        return true;
    }

    /**
     * All match.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#allMatch(Object[], com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean allMatch(final T[] a, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(a)) {
            return true;
        }

        for (T e : a) {
            if (filter.test(e) == false) {
                return false;
            }
        }

        return true;
    }

    /**
     * Any match.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#anyMatch(Collection, com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean anyMatch(final Collection c, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(c)) {
            return false;
        }

        for (T e : c) {
            if (filter.test(e)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Any match.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#anyMatch(Object[], com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean anyMatch(final T[] a, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(a)) {
            return false;
        }

        for (T e : a) {
            if (filter.test(e)) {
                return true;
            }
        }

        return false;
    }

    /**
     * None match.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#noneMatch(Collection, com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean noneMatch(final Collection c, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(c)) {
            return true;
        }

        for (T e : c) {
            if (filter.test(e)) {
                return false;
            }
        }

        return true;
    }

    /**
     * None match.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#noneMatch(Object[], com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean noneMatch(final T[] a, final Throwables.Predicate filter) throws E {
        if (N.isNullOrEmpty(a)) {
            return true;
        }

        for (T e : a) {
            if (filter.test(e)) {
                return false;
            }
        }

        return true;
    }

    /**
     * N match.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param atLeast the at least
     * @param atMost the at most
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#nMatch(Collection, int, int, com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean nMatch(final Collection c, final int atLeast, final int atMost,
            final Throwables.Predicate filter) throws E {
        N.checkArgNotNegative(atLeast, "atLeast");
        N.checkArgNotNegative(atMost, "atMost");
        N.checkArgument(atLeast <= atMost, "'atLeast' must be <= 'atMost'");

        long cnt = 0;

        for (T e : c) {
            if (filter.test(e)) {
                if (++cnt > atMost) {
                    return false;
                }
            }
        }

        return cnt >= atLeast && cnt <= atMost;
    }

    /**
     * N match.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param atLeast the at least
     * @param atMost the at most
     * @param filter the filter
     * @return true, if successful
     * @throws E the e
     * @deprecated replaced by {@code N#nMatch(Object[], int, int, com.landawn.abacus.util.Try.Predicate)}
     */
    @Deprecated
    public static  boolean nMatch(final T[] a, final int atLeast, final int atMost, final Throwables.Predicate filter)
            throws E {
        N.checkArgNotNegative(atLeast, "atLeast");
        N.checkArgNotNegative(atMost, "atMost");
        N.checkArgument(atLeast <= atMost, "'atLeast' must be <= 'atMost'");

        long cnt = 0;

        for (T e : a) {
            if (filter.test(e)) {
                if (++cnt > atMost) {
                    return false;
                }
            }
        }

        return cnt >= atLeast && cnt <= atMost;
    }

    /**
     * For each pair.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param action the action
     * @throws E the e
     */
    public static  void forEachPair(final Collection c, final Throwables.BiConsumer action)
            throws E {
        forEachPair(c, action, 1);
    }

    /**
     * For each pair.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param action the action
     * @param increment the increment
     * @throws E the e
     */
    public static  void forEachPair(final Collection c, final Throwables.BiConsumer action,
            final int increment) throws E {
        N.checkArgNotNull(action);
        final int windowSize = 2;
        N.checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment);

        if (N.isNullOrEmpty(c)) {
            return;
        }

        final Iterator iter = c.iterator();
        Iterators.forEachPair(iter, action, increment);
    }

    /**
     * For each pair.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param action the action
     * @throws E the e
     */
    public static  void forEachPair(final T[] a, final Throwables.BiConsumer action) throws E {
        forEachPair(a, action, 1);
    }

    /**
     * For each pair.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param action the action
     * @param increment the increment
     * @throws E the e
     */
    public static  void forEachPair(final T[] a, final Throwables.BiConsumer action, final int increment)
            throws E {
        N.checkArgNotNull(action);
        final int windowSize = 2;
        N.checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment);

        if (N.isNullOrEmpty(a)) {
            return;
        }

        final Iterator iter = ObjIterator.of(a);
        Iterators.forEachPair(iter, action, increment);
    }

    /**
     * For each triple.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param action the action
     * @throws E the e
     */
    public static  void forEachTriple(final Collection c,
            final Throwables.TriConsumer action) throws E {
        forEachTriple(c, action, 1);
    }

    /**
     * For each triple.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param action the action
     * @param increment the increment
     * @throws E the e
     */
    public static  void forEachTriple(final Collection c,
            final Throwables.TriConsumer action, final int increment) throws E {
        N.checkArgNotNull(action);
        final int windowSize = 3;
        N.checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment);

        if (N.isNullOrEmpty(c)) {
            return;
        }

        final Iterator iter = c.iterator();
        Iterators.forEachTriple(iter, action, increment);
    }

    /**
     * For each triple.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param action the action
     * @throws E the e
     */
    public static  void forEachTriple(final T[] a, final Throwables.TriConsumer action) throws E {
        forEachTriple(a, action, 1);
    }

    /**
     * For each triple.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param action the action
     * @param increment the increment
     * @throws E the e
     */
    public static  void forEachTriple(final T[] a, final Throwables.TriConsumer action,
            final int increment) throws E {
        N.checkArgNotNull(action);
        final int windowSize = 3;
        N.checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment);

        if (N.isNullOrEmpty(a)) {
            return;
        }

        final Iterator iter = ObjIterator.of(a);
        Iterators.forEachTriple(iter, action, increment);
    }

    /**
     * Take while.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List takeWhile(final Collection c, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.size(c)));

        if (N.isNullOrEmpty(c)) {
            return result;
        }

        for (T e : c) {
            if (filter.test(e)) {
                result.add(e);
            } else {
                break;
            }
        }

        return result;
    }

    /**
     * Take while.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List takeWhile(final T[] a, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.len(a)));

        if (N.isNullOrEmpty(a)) {
            return result;
        }

        for (T e : a) {
            if (filter.test(e)) {
                result.add(e);
            } else {
                break;
            }
        }

        return result;
    }

    /**
     * Take while inclusive.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List takeWhileInclusive(final Collection c, final Throwables.Predicate filter)
            throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.size(c)));

        if (N.isNullOrEmpty(c)) {
            return result;
        }

        for (T e : c) {
            result.add(e);

            if (filter.test(e) == false) {
                break;
            }
        }

        return result;
    }

    /**
     * Take while inclusive.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List takeWhileInclusive(final T[] a, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.len(a)));

        if (N.isNullOrEmpty(a)) {
            return result;
        }

        for (T e : a) {
            result.add(e);

            if (filter.test(e) == false) {
                break;
            }
        }

        return result;
    }

    /**
     * Drop while.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List dropWhile(final Collection c, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.size(c)));

        if (N.isNullOrEmpty(c)) {
            return result;
        }

        final Iterator iter = c.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;
    }

    /**
     * Drop while.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List dropWhile(final T[] a, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.len(a)));

        if (N.isNullOrEmpty(a)) {
            return result;
        }

        final int len = a.length;
        int idx = 0;

        while (idx < len && filter.test(a[idx]) == true) {
            idx++;
        }

        while (idx < len) {
            result.add(a[idx++]);
        }

        return result;
    }

    /**
     * Skip until.
     *
     * @param  the generic type
     * @param  the element type
     * @param c the c
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List skipUntil(final Collection c, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.size(c)));

        if (N.isNullOrEmpty(c)) {
            return result;
        }

        final Iterator iter = c.iterator();
        T e = null;

        while (iter.hasNext()) {
            e = iter.next();

            if (filter.test(e)) {
                result.add(e);
                break;
            }
        }

        while (iter.hasNext()) {
            result.add(iter.next());
        }

        return result;
    }

    /**
     * Skip until.
     *
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param filter the filter
     * @return the list
     * @throws E the e
     */
    public static  List skipUntil(final T[] a, final Throwables.Predicate filter) throws E {
        N.checkArgNotNull(filter);

        final List result = new ArrayList<>(N.min(9, N.len(a)));

        if (N.isNullOrEmpty(a)) {
            return result;
        }

        final int len = a.length;
        int idx = 0;

        while (idx < len && filter.test(a[idx]) == false) {
            idx++;
        }

        while (idx < len) {
            result.add(a[idx++]);
        }

        return result;
    }

    /**
     *
     * @param 
     * @param 
     * @param a
     * @param b
     * @return
     * @see N#crossJoin(Collection, Collection)
     * @deprecated replaced by {@code N.crossJoin(Collection, Collection)}
     */
    @Deprecated
    public static  List> crossJoin(final Collection a, final Collection b) {
        return crossJoin(a, b, Fn. tuple2());
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param 
     * @param a
     * @param b
     * @param func
     * @return
     * @throws E
     * @see N#crossJoin(Collection, Collection, com.landawn.abacus.util.Throwables.BiFunction)
     * @deprecated replaced by {@code N.crossJoin(Collection, Collection, com.landawn.abacus.util.Try.BiFunction)}
     */
    @Deprecated
    public static  List crossJoin(final Collection a, final Collection b,
            final Throwables.BiFunction func) throws E {
        N.checkArgNotNull(func, "func");

        final List result = new ArrayList<>(N.size(a) * N.size(b));

        if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
            return result;
        }

        for (T ae : a) {
            for (U be : b) {
                result.add(func.apply(ae, be));
            }
        }

        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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param b the b
     * @param leftKeyMapper the left key mapper
     * @param rightKeyMapper the right key mapper
     * @return the list
     * @throws E the e
     * @throws E2 the e2
     * @see N#innerJoin(Collection, Collection, com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.Throwables.Function)
     * @see sql join
     * @deprecated replaced by {@code N.innerJoin(Collection, Collection, com.landawn.abacus.util.Try.Function, com.landawn.abacus.util.Try.Function)}
     */
    @Deprecated
    public static  List> innerJoin(final Collection a, final Collection b,
            final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) throws E, E2 {
        final List> result = new ArrayList<>(N.min(9, N.size(a), N.size(b)));

        if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
            return result;
        }

        final ListMultimap rightKeyMap = ListMultimap.from(b, rightKeyMapper);

        for (T left : a) {
            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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param b the b
     * @param predicate the predicate
     * @return the list
     * @throws E the e
     * @see N#innerJoin(Collection, Collection, com.landawn.abacus.util.Throwables.BiPredicate)
     * @see sql join
     * @deprecated replaced by {@code N.innerJoin(Collection, Collection, com.landawn.abacus.util.Try.BiPredicate)}
     */
    @Deprecated
    public static  List> innerJoin(final Collection a, final Collection b,
            final Throwables.BiPredicate predicate) throws E {
        final List> result = new ArrayList<>(N.min(9, N.size(a), N.size(b)));

        if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
            return result;
        }

        for (T left : a) {
            for (U right : b) {
                if (predicate.test(left, right)) {
                    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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param b the b
     * @param leftKeyMapper the left key mapper
     * @param rightKeyMapper the right key mapper
     * @return the list
     * @throws E the e
     * @throws E2 the e2
     * @see N#fullJoin(Collection, Collection, com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.Throwables.Function)
     * @see sql join
     * @deprecated replaced by {@code N.fullJoin(Collection, Collection, com.landawn.abacus.util.Try.Function, com.landawn.abacus.util.Try.Function)}
     */
    @Deprecated
    public static  List> fullJoin(final Collection a, final Collection b,
            final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) throws E, E2 {
        final List> result = new ArrayList<>(N.max(9, N.size(a), N.size(b)));

        if (N.isNullOrEmpty(a)) {
            for (T left : a) {
                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 : a) {
                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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param b the b
     * @param predicate the predicate
     * @return the list
     * @throws E the e
     * @see N#fullJoin(Collection, Collection, com.landawn.abacus.util.Throwables.BiPredicate)
     * @see sql join
     * @deprecated replaced by {@code N.fullJoin(Collection, Collection, com.landawn.abacus.util.Try.BiPredicate)}
     */
    @Deprecated
    public static  List> fullJoin(final Collection a, final Collection b,
            final Throwables.BiPredicate predicate) throws E {
        final List> result = new ArrayList<>(N.max(9, N.size(a), N.size(b)));

        if (N.isNullOrEmpty(a)) {
            for (T left : a) {
                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 Map joinedRights = new IdentityHashMap<>();

            for (T left : a) {
                boolean joined = false;

                for (U right : b) {
                    if (predicate.test(left, right)) {
                        result.add(Pair.of(left, right));
                        joinedRights.put(right, right);
                        joined = true;
                    }
                }

                if (joined == false) {
                    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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param b the b
     * @param leftKeyMapper the left key mapper
     * @param rightKeyMapper the right key mapper
     * @return the list
     * @throws E the e
     * @throws E2 the e2
     * @see N#leftJoin(Collection, Collection, com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.Throwables.Function)
     * @see sql join
     * @deprecated replaced by {@code N.leftJoin(Collection, Collection, com.landawn.abacus.util.Try.Function, com.landawn.abacus.util.Try.Function)}
     */
    @Deprecated
    public static  List> leftJoin(final Collection a, final Collection b,
            final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) throws E, E2 {
        final List> result = new ArrayList<>(N.size(a));

        if (N.isNullOrEmpty(a)) {
            return result;
        } else if (N.isNullOrEmpty(b)) {
            for (T left : a) {
                result.add(Pair.of(left, (U) null));
            }
        } else {
            final ListMultimap rightKeyMap = ListMultimap.from(b, rightKeyMapper);

            for (T left : a) {
                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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param b the b
     * @param predicate the predicate
     * @return the list
     * @throws E the e
     * @see N#leftJoin(Collection, Collection, com.landawn.abacus.util.Throwables.BiPredicate)
     * @see sql join
     * @deprecated replaced by {@code N.leftJoin(Collection, Collection, com.landawn.abacus.util.Try.BiPredicate)}
     */
    @Deprecated
    public static  List> leftJoin(final Collection a, final Collection b,
            final Throwables.BiPredicate predicate) throws E {
        final List> result = new ArrayList<>(N.size(a));

        if (N.isNullOrEmpty(a)) {
            return result;
        } else if (N.isNullOrEmpty(b)) {
            for (T left : a) {
                result.add(Pair.of(left, (U) null));
            }
        } else {
            for (T left : a) {
                boolean joined = false;

                for (U right : b) {
                    if (predicate.test(left, right)) {
                        result.add(Pair.of(left, right));
                        joined = true;
                    }
                }

                if (joined == false) {
                    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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param  the generic type
     * @param a the a
     * @param b the b
     * @param leftKeyMapper the left key mapper
     * @param rightKeyMapper the right key mapper
     * @return the list
     * @throws E the e
     * @throws E2 the e2
     * @see N#rightJoin(Collection, Collection, com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.Throwables.Function)
     * @see sql join
     * @deprecated replaced by {@code N.rightJoin(Collection, Collection, com.landawn.abacus.util.Try.Function, com.landawn.abacus.util.Try.Function)}
     */
    @Deprecated
    public static  List> rightJoin(final Collection a, final Collection b,
            final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) throws E, E2 {
        final List> result = new ArrayList<>(N.size(b));

        if (N.isNullOrEmpty(b)) {
            return result;
        } else if (N.isNullOrEmpty(a)) {
            for (U right : b) {
                result.add(Pair.of((T) null, right));
            }
        } else {
            final ListMultimap leftKeyMap = ListMultimap.from(a, 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  the generic type
     * @param  the generic type
     * @param  the element type
     * @param a the a
     * @param b the b
     * @param predicate the predicate
     * @return the list
     * @throws E the e
     * @see N#rightJoin(Collection, Collection, com.landawn.abacus.util.Throwables.BiPredicate)
     * @see sql join
     * @deprecated replaced by {@code N.rightJoin(Collection, Collection, com.landawn.abacus.util.Try.BiPredicate)}
     */
    @Deprecated
    public static  List> rightJoin(final Collection a, final Collection b,
            final Throwables.BiPredicate predicate) throws E {
        final List> result = new ArrayList<>(N.size(b));

        if (N.isNullOrEmpty(b)) {
            return result;
        } else if (N.isNullOrEmpty(a)) {
            for (U right : b) {
                result.add(Pair.of((T) null, right));
            }
        } else {
            for (U right : b) {
                boolean joined = false;

                for (T left : a) {
                    if (predicate.test(left, right)) {
                        result.add(Pair.of(left, right));
                        joined = true;
                    }
                }

                if (joined == false) {
                    result.add(Pair.of((T) null, right));
                }
            }
        }

        return result;
    }

    /**
     * The Class Slice.
     *
     * @param  the generic type
     */
    static final class Slice extends ImmutableCollection {

        /** The from index. */
        private final int fromIndex;

        /** The to index. */
        private final int toIndex;

        /**
         * Instantiates a new sub collection.
         *
         * @param a the a
         * @param fromIndex the from index
         * @param toIndex the to index
         */
        Slice(final T[] a, final int fromIndex, final int toIndex) {
            this(Array.asList(a), fromIndex, toIndex);
        }

        /**
         * Instantiates a new sub collection.
         *
         * @param c the c
         * @param fromIndex the from index
         * @param toIndex the to index
         */
        Slice(final Collection c, final int fromIndex, final int toIndex) {
            super(c);
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }

        /**
         * Contains.
         *
         * @param o the o
         * @return true, if successful
         */
        @Override
        public boolean contains(Object o) {
            final Iterator iter = this.iterator();

            while (iter.hasNext()) {
                if (N.equals(iter.next(), o)) {
                    return true;
                }
            }

            return false;
        }

        /**
         * Contains all.
         *
         * @param c the c
         * @return true, if successful
         */
        @Override
        public boolean containsAll(final Collection c) {
            for (Object e : c) {
                if (contains(e) == false) {
                    return false;
                }
            }

            return true;
        }

        /**
         * Checks if is empty.
         *
         * @return true, if is empty
         */
        @Override
        public boolean isEmpty() {
            return size() == 0;
        }

        /**
         * Size.
         *
         * @return the int
         */
        @Override
        public int size() {
            return toIndex - fromIndex;
        }

        /**
         * Iterator.
         *
         * @return the iterator
         */
        @Override
        public Iterator iterator() {
            final Iterator iter = coll == null ? ObjIterator. empty() : coll.iterator();

            if (fromIndex > 0) {
                int offset = 0;

                while (offset++ < fromIndex) {
                    iter.next();
                }
            }

            return new Iterator() {
                private int cursor = fromIndex;

                @Override
                public boolean hasNext() {
                    return cursor < toIndex;
                }

                @Override
                public T next() {
                    if (cursor >= toIndex) {
                        throw new NoSuchElementException();
                    }

                    cursor++;
                    return iter.next();
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            };
        }

        /**
         * To array.
         *
         * @return the object[]
         */
        @Override
        public Object[] toArray() {
            final Iterator iter = this.iterator();
            final Object[] a = new Object[size()];

            for (int i = 0, len = a.length; i < len; i++) {
                a[i] = iter.next();
            }

            return a;
        }

        /**
         * To array.
         *
         * @param  the generic type
         * @param a the a
         * @return the a[]
         */
        @Override
        public  A[] toArray(A[] a) {
            if (a.length < size()) {
                a = N.copyOf(a, size());
            }

            final Iterator iter = this.iterator();

            for (int i = 0, len = a.length; i < len; i++) {
                a[i] = (A) iter.next();
            }

            return a;
        }
    }
}