/* * Copyright (C) 2011 The Guava Authors * * 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.google.common.collect; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Function; import com.google.common.collect.Multiset.Entry; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; /** * Utilities for dealing with sorted collections of all types. * * @author Louis Wasserman */ @GwtCompatible final class SortedIterables { private SortedIterables() {} /** * Returns {@code true} if {@code elements} is a sorted collection using an ordering equivalent * to {@code comparator}. */ public static boolean hasSameComparator(Comparator comparator, Iterable elements) { checkNotNull(comparator); checkNotNull(elements); Comparator comparator2; if (elements instanceof SortedSet) { SortedSet sortedSet = (SortedSet) elements; comparator2 = sortedSet.comparator(); if (comparator2 == null) { comparator2 = (Comparator) Ordering.natural(); } } else if (elements instanceof SortedIterable) { comparator2 = ((SortedIterable) elements).comparator(); } else { comparator2 = null; } return comparator.equals(comparator2); } /** * Returns a sorted collection of the unique elements according to the specified comparator. Does * not check for null. */ @SuppressWarnings("unchecked") public static Collection sortedUnique( Comparator comparator, Iterator elements) { SortedSet sortedSet = Sets.newTreeSet(comparator); Iterators.addAll(sortedSet, elements); return sortedSet; } /** * Returns a sorted collection of the unique elements according to the specified comparator. Does * not check for null. */ @SuppressWarnings("unchecked") public static Collection sortedUnique( Comparator comparator, Iterable elements) { if (elements instanceof Multiset) { elements = ((Multiset) elements).elementSet(); } if (elements instanceof Set) { if (hasSameComparator(comparator, elements)) { return (Set) elements; } List list = Lists.newArrayList(elements); Collections.sort(list, comparator); return list; } E[] array = (E[]) Iterables.toArray(elements); if (!hasSameComparator(comparator, elements)) { Arrays.sort(array, comparator); } return uniquifySortedArray(comparator, array); } private static Collection uniquifySortedArray( Comparator comparator, E[] array) { if (array.length == 0) { return Collections.emptySet(); } int length = 1; for (int i = 1; i < array.length; i++) { int cmp = comparator.compare(array[i], array[length - 1]); if (cmp != 0) { array[length++] = array[i]; } } if (length < array.length) { array = ObjectArrays.arraysCopyOf(array, length); } return Arrays.asList(array); } /** * Returns a collection of multiset entries representing the counts of the distinct elements, in * sorted order. Does not check for null. */ public static Collection> sortedCounts( Comparator comparator, Iterator elements) { TreeMultiset multiset = TreeMultiset.create(comparator); Iterators.addAll(multiset, elements); return multiset.entrySet(); } /** * Returns a collection of multiset entries representing the counts of the distinct elements, in * sorted order. Does not check for null. */ public static Collection> sortedCounts( Comparator comparator, Iterable elements) { if (elements instanceof Multiset) { Multiset multiset = (Multiset) elements; if (hasSameComparator(comparator, elements)) { return multiset.entrySet(); } List> entries = Lists.newArrayList(multiset.entrySet()); Collections.sort( entries, Ordering.from(comparator).onResultOf(new Function, E>() { @Override public E apply(Entry entry) { return entry.getElement(); } })); return entries; } else if (elements instanceof Set) { // known distinct Collection sortedElements; if (hasSameComparator(comparator, elements)) { sortedElements = (Collection) elements; } else { List list = Lists.newArrayList(elements); Collections.sort(list, comparator); sortedElements = list; } return singletonEntries(sortedElements); } else if (hasSameComparator(comparator, elements)) { E current = null; int currentCount = 0; List> sortedEntries = Lists.newArrayList(); for (E e : elements) { if (currentCount > 0) { if (comparator.compare(current, e) == 0) { currentCount++; } else { sortedEntries.add(Multisets.immutableEntry(current, currentCount)); current = e; currentCount = 1; } } else { current = e; currentCount = 1; } } if (currentCount > 0) { sortedEntries.add(Multisets.immutableEntry(current, currentCount)); } return sortedEntries; } TreeMultiset multiset = TreeMultiset.create(comparator); Iterables.addAll(multiset, elements); return multiset.entrySet(); } static Collection> singletonEntries(Collection set) { return Collections2.transform(set, new Function>() { @Override public Entry apply(E elem) { return Multisets.immutableEntry(elem, 1); } }); } }