com.google.common.collect.Comparators Maven / Gradle / Ivy
Show all versions of google-collect Show documentation
/*
* Copyright (C) 2007 Google Inc.
*
* 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 com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Nullable;
import com.google.common.base.Objects;
import static com.google.common.base.Preconditions.checkContentsNotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* Standard comparators and utilities for creating and working with comparators.
*
* Some of these methods return an {@link Ordering}, a serializable class
* that implements {@link Comparator} and includes many additional methods.
*
*
Several method signatures include {@code } with a
* raw {@link Comparable}, instead of
* {@code }. That's necessary to support classes
* defined without generics.
*
* @author Jared Levy
* @author Kevin Bourrillion
* @author Mike Bostock
*/
public final class Comparators {
private Comparators() {}
/**
* Returns a comparator that uses the natural ordering of the values.
*
* @see java.util.Collections#reverseOrder()
*/
@SuppressWarnings("unchecked") // see explanation in class Javadoc
public static Ordering naturalOrder() {
return (Ordering) NATURAL_ORDER;
}
/** @see #naturalOrder */
@SuppressWarnings("unchecked") // see explanation in class Javadoc
private static final Ordering NATURAL_ORDER
= new Ordering() {
public int compare(Comparable left, Comparable right) {
if (left == right) {
return 0;
}
/*
* compareTo() may throw a ClassCastException if the elements are not
* mutually comparable.
*/
@SuppressWarnings("unchecked")
int result = left.compareTo(right);
return result;
}
// preserve singleton-ness, so equals() and hashCode() work correctly
private Object readResolve() {
return NATURAL_ORDER;
}
private static final long serialVersionUID = 4773556737939767552L;
};
/**
* Returns a comparator that treats {@code null} as less than all other
* values and uses {@code comparator} to compare non-null values.
*/
public static Ordering nullLeastOrder(Comparator comparator) {
checkNotNull(comparator);
return new NullHandlingOrdering(comparator) {
@Override int compareNullAndNonNull() {
return -1;
}
private static final long serialVersionUID = 0x5AF3C26EB419D807L;
};
}
/**
* Returns a comparator that uses the natural ordering of the values, but also
* handles null values, treating them as less than all other values.
*/
@SuppressWarnings("unchecked") // see explanation in class Javadoc
public static Ordering nullLeastOrder() {
return (Ordering) NULL_LEAST_ORDER;
}
@SuppressWarnings("unchecked") // see explanation in class Javadoc
private static final Ordering NULL_LEAST_ORDER
= nullLeastOrder(NATURAL_ORDER);
/**
* Returns a comparator that treats {@code null} as greater than all other
* values and uses the given comparator to compare non-null values.
*/
public static Ordering nullGreatestOrder(Comparator comparator) {
checkNotNull(comparator);
return new NullHandlingOrdering(comparator) {
@Override int compareNullAndNonNull() {
return 1;
}
private static final long serialVersionUID = 0xB17D30AE62485CF9L;
};
}
/**
* Returns a comparator that uses the natural ordering of the values, but also
* handles null values, treating them as greater than all other values.
*/
@SuppressWarnings("unchecked") // see explanation in class Javadoc
public static Ordering nullGreatestOrder() {
return (Ordering) NULL_GREATEST_ORDER;
}
// TODO: Add readResolve methods to NULL_GREATEST_ORDER and NULL_LEAST_ORDER
@SuppressWarnings("unchecked") // see explanation in class Javadoc
private static final Ordering NULL_GREATEST_ORDER
= nullGreatestOrder(NATURAL_ORDER);
/**
* Returns a comparator which tries each given comparator in order until a
* non-zero result is found, returning this result, and returning zero only if
* all comparators return zero.
*
* The returned comparator is a "view" of the specified {@code rest} array;
* changes to the array will be reflected in the behavior of the returned
* comparator.
*
*
TODO: Add {@code compound} methods that take 2, 3, or 4 arguments, so
* the calling code doesn't need to say
* {@code @SuppressWarnings("unchecked")}.
*
* @param primary the primary comparator
* @param secondary the secondary comparator
* @param rest additional comparators to invoke as necessary
* @see #compound(List)
*/
@SuppressWarnings("unchecked") // TODO: check that this is right
public static Ordering compound(Comparator super T> primary,
Comparator super T> secondary, Comparator super T>... rest) {
// TODO: is this really the best way? if so, explain why.
Comparator primaryT = (Comparator) primary;
Comparator secondaryT = (Comparator) secondary;
Comparator[] restT = (Comparator[]) rest;
return compound(Lists.asList(primaryT, secondaryT, restT));
}
/**
* Returns a comparator which tries each given comparator in order until a
* non-zero result is found, returning this result, and returning zero only if
* all comparators return zero.
*
* The returned comparator is a "view" of the specified {@code List}
* instance; changes to the collection of comparators will be reflected in the
* behavior of the returned comparator.
*
* @param comparators a collection of comparators to try in order
*/
public static Ordering compound(
List extends Comparator super T>> comparators) {
return new CompoundOrder(comparators);
}
/** @see Comparators#compound(List) */
static class CompoundOrder extends Ordering {
private final List extends Comparator super T>> comparators;
CompoundOrder(List extends Comparator super T>> comparators) {
this.comparators = checkContentsNotNull(comparators);
}
public int compare(T left, T right) {
if (left == right) {
return 0;
}
for (Comparator super T> comparator : comparators) {
int result = comparator.compare(left, right);
if (result != 0) {
return result;
}
}
return 0;
}
@Override public boolean equals(Object object) {
if (object instanceof CompoundOrder>) {
CompoundOrder> that = (CompoundOrder>) object;
return (this.comparators).equals(that.comparators);
}
return false;
}
@Override public int hashCode() {
return comparators.hashCode();
}
private static final long serialVersionUID = 5950260273184699058L;
}
/**
* Creates a comparator that compares any two items by applying a function to
* each of them and using the natural ordering of the results.
*
* @param function the function returning the value to compare. The function
* should never return {@code null}.
* @return the generated comparator
*/
@SuppressWarnings("unchecked") // see explanation in class Javadoc
public static Ordering
fromFunction(Function function) {
return new TransformingNaturalOrder(function);
}
/** @see Comparators#fromFunction(Function) */
@SuppressWarnings("unchecked") // see explanation in class Javadoc
private static class TransformingNaturalOrder
extends Ordering {
private final Function function;
TransformingNaturalOrder(Function function) {
this.function = checkNotNull(function);
}
public int compare(F left, F right) {
T leftTransformed = function.apply(left);
T rightTransformed = function.apply(right);
/*
* Let this throw a ClassCastException if T is a bizarre Comparable that
* can't be compared to itself.
*/
@SuppressWarnings("unchecked")
int result = leftTransformed.compareTo(rightTransformed);
return result;
}
@Override public boolean equals(Object object) {
if (object instanceof TransformingNaturalOrder, ?>) {
TransformingNaturalOrder, ?> that
= (TransformingNaturalOrder, ?>) object;
return (this.function).equals(that.function);
}
return false;
}
@Override public int hashCode() {
return function.hashCode();
}
private static final long serialVersionUID = 4211028873657370047L;
}
/**
* Creates a comparator that compares any two items by applying a function to
* each of them and using the supplied comparator to compare the results.
*
* @param function the function returning the value to compare
* @param comparator the comparator that receives the function output
* @return the generated comparator
*/
public static Ordering fromFunction(
Function function, Comparator super T> comparator) {
return new TransformingOrder(function, comparator);
}
/** @see Comparators#fromFunction(Function,Comparator) */
static class TransformingOrder extends Ordering {
private final Function function;
private final Comparator super T> comparator;
TransformingOrder(
Function function, Comparator super T> comparator) {
this.function = checkNotNull(function);
this.comparator = checkNotNull(comparator);
}
public int compare(F left, F right) {
return comparator.compare(function.apply(left), function.apply(right));
}
@Override public boolean equals(Object object) {
if (object instanceof TransformingOrder, ?>) {
TransformingOrder, ?> that = (TransformingOrder, ?>) object;
return (this.function).equals(that.function)
&& (this.comparator).equals(that.comparator);
}
return false;
}
@Override public int hashCode() {
return Objects.hashCode(function, comparator);
}
private static final long serialVersionUID = 5364346520892770700L;
}
/**
* A comparator that compares objects by the natural ordering of their string
* representations as returned by {@code toString}. Does not support null
* values.
*/
public static final Ordering