com.zimbra.common.util.ListUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.common.util.ListUtil.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */

package com.zimbra.common.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

public class ListUtil {

    /**
     * Returns {@code true} if the collection is {@code null} or empty.
     */
    public static boolean isEmpty(Collection<?> c) {
        return c == null || c.isEmpty();
    }

    /**
     * Returns either {@code c} or an empty collection if {@code c} is {@code null}.
     */
    @SuppressWarnings("unchecked")
    public static <T> Collection<T> nullToEmpty(Collection<T> c) {
        return (c == null ? (Collection<T>) Collections.emptyList() : c);
    }

    /**
     * Returns the first element, or {@code null} if the collection is
     * {@code null} or empty.
     */
    public static <T> T getFirstElement(Iterable<T> iterable) {
        return iterable == null ? null : Iterables.getFirst(iterable, null);
    }

    /**
     * Given two unsorted lists, return TRUE if they contain exactly the same things
     * (regardless of order)
     *
     * @param <T>
     * @param lhs
     * @param rhs
     * @return
     */
    public static <T> boolean listsEqual(List<T> lhs, List<T> rhs) {
        if (lhs.size() != rhs.size())
            return false;

        HashSet<T> set = new HashSet<T>();
        set.addAll(lhs);
        for (T t : rhs) {
            if (!set.remove(t))
                return false;
        }
        return (set.size() == 0);
    }

    /**
     * Merge two sorted Lists
     *
     * I could have used the Java Set collection here...unfortunately the only ordered set
     * is their TreeSet, and set union/subtraction therefore take NlogN with a pretty big
     * constant overhead.
     *
     * @param dest
     * @param src
     */
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void mergeSortedLists(List<T> dest, List<T>[] src,
            boolean removeDuplicates) {
        int numSrc = 0;
        for (int i = 0; i < src.length; i++) {
            if (src[i] != null) {
                numSrc++;
            }
        }

        if (numSrc == 1) {
            for (int i = 0; i < src.length; i++) {
                if (src[i] != null) {
                    dest.addAll(src[i]);
                    return;
                }
            }
        }

        Iterator<T> iter[] = new Iterator[numSrc];
        int iterOffset = 0;
        for (int i = 0; i < src.length; i++) {
            if (src[i] != null) {
                iter[iterOffset++] = src[i].iterator();
            }
        }

        int numItersActive = src.length;

        // holds the next values of each iterator
        T nextValue[] = (T[]) new Comparable[src.length];

        T lowestValue = null;
        int lowestValueOffset = -1;

        T lastAdded = null;

        // prime the pump
        for (int i = 0; i < iter.length; i++) {
            if (iter[i].hasNext()) {
                nextValue[i] = iter[i].next();

                if (lowestValue == null || (lowestValue.compareTo(nextValue[i]) > 0)) {
                    lowestValue = nextValue[i];
                    lowestValueOffset = i;
                }
            } else {
                iter[i] = null;
                numItersActive--;
            }
        }

        while (numItersActive > 0) {
            // grab lowest value from the src list, put it on the return list
            if ((!removeDuplicates) || (lastAdded == null)) {
                dest.add(nextValue[lowestValueOffset]);
                lastAdded = nextValue[lowestValueOffset];
                nextValue[lowestValueOffset] = null;
            } else {
                if (!lastAdded.equals(nextValue[lowestValueOffset])) {
                    dest.add(nextValue[lowestValueOffset]);
                    lastAdded = nextValue[lowestValueOffset];
                }
                nextValue[lowestValueOffset] = null;
            }

            // iterate the proper src list
            if (iter[lowestValueOffset].hasNext()) {
                nextValue[lowestValueOffset] = iter[lowestValueOffset].next();
            } else {
                iter[lowestValueOffset] = null;
                numItersActive--;
            }

            // find the next-lowest-value
            lowestValue = null;
            lowestValueOffset = -1;
            for (int i = 0; i < src.length; i++) {
                if (lowestValue == null || ((nextValue[i] != null) && (lowestValue.compareTo(nextValue[i]) > 0))) {
                    lowestValue = nextValue[i];
                    lowestValueOffset = i;
                }
            }
        }
    }

    /**
     * @param a
     * @param b
     *
     * Subtract two sorted lists
     *
     * returns (a-b);
     */
    public static <T> List<T> subtractSortedLists(List<T> a, List<T> b, Comparator<T> comparator) {
        List<T> result = new ArrayList<T>(a.size());

        Iterator<T> aIter = a.iterator();
        Iterator<T> bIter = b.iterator();

        T aVal = null;
        if (aIter.hasNext()) {
            aVal = aIter.next();
        }
        T bVal = null;
        if (bIter.hasNext()) {
            bVal = bIter.next();
        }

        while (aVal != null) {
            if (bVal == null) {
                result.add(aVal);
            } else {
                int comp = comparator.compare(aVal, bVal);
                if (comp < 0) {
                    // a < b
                    result.add(aVal);
                } else if (comp > 0) {
                    // a > b
                    if (bIter.hasNext()) {
                        bVal = bIter.next();
                    } else {
                        bVal = null;
                    }
                    continue; // DON'T move A fwd...
                } else {
                    // a==b, so skip A!
                }
            }

            if (aIter.hasNext()) {
                aVal = aIter.next();
            } else {
                aVal = null;
            }
        }

        return result;
    }

    /**
     * Splits a <code>Collection</code> into <i>n</i> <code>List</code>s.
     * Lists <i>1</i> through <i>n-1</i> are of size <code>listSize</code>.  List <i>n</i>
     * contains the remaining elements.
     *
     * @return the split lists.  Returns <tt>null</tt> if <tt>c</tt> is <tt>null</tt>
     * or an empty <tt>List</tt> if <tt>c</tt> is empty.
     */
    public static <E> List<List<E>> split(Collection<E> c, int listSize) {
        if (c == null) {
            return null;
        }
        List<List<E>> splitLists = new ArrayList<List<E>>();
        if (c.size() == 0) {
            return splitLists;
        }

        List<E> curList = new ArrayList<E>(listSize);
        int i = 0;

        for (E item : c) {
            if (i == listSize) {
                splitLists.add(curList);
                curList = new ArrayList<E>(listSize);
                i = 0;
            }
            curList.add(item);
            i++;
        }
        splitLists.add(curList);

        return splitLists;
    }

    private static class Test {

        @SuppressWarnings("unchecked")
        static void doit() {
            List<Integer>[] in = new List[5];

            int i = 0;

            in[i] = new ArrayList<Integer>();
            in[i].add(Integer.valueOf(1));
            in[i].add(Integer.valueOf(3));
            in[i].add(Integer.valueOf(5));
            in[i].add(Integer.valueOf(7));
            in[i].add(Integer.valueOf(9));

            i = 1;
            in[i] = new ArrayList<Integer>();
            in[i].add(Integer.valueOf(1));
            in[i].add(Integer.valueOf(7));
            in[i].add(Integer.valueOf(12));
            in[i].add(Integer.valueOf(13));
            in[i].add(Integer.valueOf(13));

            i = 2;
            in[i] = new ArrayList<Integer>();
            in[i].add(Integer.valueOf(1));
            in[i].add(Integer.valueOf(2));
            in[i].add(Integer.valueOf(3));
            in[i].add(Integer.valueOf(4));
            in[i].add(Integer.valueOf(5));

            i = 3;
            in[i] = new ArrayList<Integer>();
            in[i].add(Integer.valueOf(5));
            in[i].add(Integer.valueOf(6));
            in[i].add(Integer.valueOf(7));
            in[i].add(Integer.valueOf(8));
            in[i].add(Integer.valueOf(9));

            i = 4;
            in[i] = new ArrayList<Integer>();
            in[i].add(Integer.valueOf(100));
            in[i].add(Integer.valueOf(101));
            in[i].add(Integer.valueOf(102));
            in[i].add(Integer.valueOf(103));
            in[i].add(Integer.valueOf(104));

            List<Integer> test;

            test = new ArrayList<Integer>();
            mergeSortedLists(test, in, false);
            System.out.print("DUPES_NOT_REMOVED: ");
            for (Integer cur : test) {
                System.out.print(cur + ", ");
            }
            System.out.println();

            test = new ArrayList<Integer>();
            mergeSortedLists(test, in, true);
            System.out.print("DUPES_REMOVED: ");
            for (Integer cur : test) {
                System.out.print(cur + ", ");
            }
            System.out.println();

            test = subtractSortedLists(in[2], in[0], new IntegerComparator());
            System.out.print("(1,2,3,4,5) - (1,3,5,7,9): ");
            for (Iterator<Integer> iter = test.iterator(); iter.hasNext();) {
                Integer cur = iter.next();
                System.out.print(cur + ", ");
            }
            System.out.println();

            test = subtractSortedLists(in[0], in[1], new IntegerComparator());
            System.out.print("(1,3,5,7,9) - (1,7,12,13,13): ");
            for (Iterator<Integer> iter = test.iterator(); iter.hasNext();) {
                Integer cur = iter.next();
                System.out.print(cur + ", ");
            }
            System.out.println();

        }

        private static class IntegerComparator implements Comparator<Integer> {
            IntegerComparator() {
            }

            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        }
    }

    /**
     * Returns a new {@code List} whose elements are the transformed versions of the data
     * stored in {@code fromIterable}.
     *
     * @param fromIterable source data
     * @param function transformation function
     */
    public static <F, T> List<T> newArrayList(Iterable<F> fromIterable, Function<? super F, ? extends T> function) {
        return Lists.newArrayList(Iterables.transform(fromIterable, function));
    }

    /**
     * Filters the given {@code Iterable} and returns a new {@code List} whose
     * elements match the {@code Predicate}.
     */
    public static <T> List<T> newArrayList(Iterable<T> unfiltered, Predicate<T> predicate) {
        return Lists.newArrayList(Iterables.filter(unfiltered, predicate));
    }

    public static void main(String[] args) {
        Test.doit();
    }
}