com.google.common.collect.SortedMaps Maven / Gradle / Ivy
Show all versions of guava Show documentation
/*
* Copyright (C) 2010 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 java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps.EntryTransformer;
/**
* Static utility methods pertaining to {@link SortedMap} instances.
*
* @author Louis Wasserman
* @since 8.0
* @deprecated Use the identical methods in {@link Maps}. This class is
* scheduled for deletion from Guava in Guava release 12.0.
*/
@Beta
@Deprecated
@GwtCompatible
public final class SortedMaps {
private SortedMaps() {}
/**
* Returns a view of a sorted map where each value is transformed by a
* function. All other properties of the map, such as iteration order, are
* left intact. For example, the code: {@code
*
* SortedMap map = ImmutableSortedMap.of("a", 4, "b", 9);
* Function sqrt =
* new Function() {
* public Double apply(Integer in) {
* return Math.sqrt((int) in);
* }
* };
* SortedMap transformed =
* Maps.transformSortedValues(map, sqrt);
* System.out.println(transformed);}
*
* ... prints {@code {a=2.0, b=3.0}}.
*
* Changes in the underlying map are reflected in this view. Conversely,
* this view supports removal operations, and these are reflected in the
* underlying map.
*
*
It's acceptable for the underlying map to contain null keys, and even
* null values provided that the function is capable of accepting null input.
* The transformed map might contain null values, if the function sometimes
* gives a null result.
*
*
The returned map is not thread-safe or serializable, even if the
* underlying map is.
*
*
The function is applied lazily, invoked when needed. This is necessary
* for the returned map to be a view, but it means that the function will be
* applied many times for bulk operations like {@link Map#containsValue} and
* {@code Map.toString()}. For this to perform well, {@code function} should
* be fast. To avoid lazy evaluation when the returned map doesn't need to be
* a view, copy the returned map into a new map of your choosing.
*
* @deprecated Use {@link Maps#transformValues(SortedMap, Function)}
*/
@Deprecated public static SortedMap transformValues(
SortedMap fromMap, final Function super V1, V2> function) {
return Maps.transformValues(fromMap, function);
}
/**
* Returns a view of a sorted map whose values are derived from the original
* sorted map's entries. In contrast to {@link #transformValues}, this
* method's entry-transformation logic may depend on the key as well as the
* value.
*
* All other properties of the transformed map, such as iteration order,
* are left intact. For example, the code:
{@code
*
* Map options =
* ImmutableSortedMap.of("verbose", true, "sort", false);
* EntryTransformer flagPrefixer =
* new EntryTransformer() {
* public String transformEntry(String key, Boolean value) {
* return value ? key : "yes" + key;
* }
* };
* SortedMap transformed =
* LabsMaps.transformSortedEntries(options, flagPrefixer);
* System.out.println(transformed);}
*
* ... prints {@code {sort=yessort, verbose=verbose}}.
*
* Changes in the underlying map are reflected in this view. Conversely,
* this view supports removal operations, and these are reflected in the
* underlying map.
*
*
It's acceptable for the underlying map to contain null keys and null
* values provided that the transformer is capable of accepting null inputs.
* The transformed map might contain null values if the transformer sometimes
* gives a null result.
*
*
The returned map is not thread-safe or serializable, even if the
* underlying map is.
*
*
The transformer is applied lazily, invoked when needed. This is
* necessary for the returned map to be a view, but it means that the
* transformer will be applied many times for bulk operations like {@link
* Map#containsValue} and {@link Object#toString}. For this to perform well,
* {@code transformer} should be fast. To avoid lazy evaluation when the
* returned map doesn't need to be a view, copy the returned map into a new
* map of your choosing.
*
*
Warning: This method assumes that for any instance {@code k} of
* {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
* that {@code k2} is also of type {@code K}. Using an {@code
* EntryTransformer} key type for which this may not hold, such as {@code
* ArrayList}, may risk a {@code ClassCastException} when calling methods on
* the transformed map.
*
* @deprecated Use {@link Maps#transformEntries(SortedMap, EntryTransformer)}
*/
@Deprecated public static SortedMap transformEntries(
final SortedMap fromMap,
EntryTransformer super K, ? super V1, V2> transformer) {
return Maps.transformEntries(fromMap, transformer);
}
/**
* Computes the difference between two sorted maps, using the comparator of
* the left map, or {@code Ordering.natural()} if the left map uses the
* natural ordering of its elements. This difference is an immutable snapshot
* of the state of the maps at the time this method is called. It will never
* change, even if the maps change at a later time.
*
* Since this method uses {@code TreeMap} instances internally, the keys of
* the right map must all compare as distinct according to the comparator
* of the left map.
*
*
Note:If you only need to know whether two sorted maps have the
* same mappings, call {@code left.equals(right)} instead of this method.
*
* @param left the map to treat as the "left" map for purposes of comparison
* @param right the map to treat as the "right" map for purposes of comparison
* @return the difference between the two maps
* @deprecated Use {@link Maps#difference(SortedMap, Map)}
*/
@Deprecated public static SortedMapDifference difference(
SortedMap left, Map extends K, ? extends V> right) {
return Maps.difference(left, right);
}
/**
* Returns the specified comparator if not null; otherwise returns {@code
* Ordering.natural()}. This method is an abomination of generics; the only
* purpose of this method is to contain the ugly type-casting in one place.
*/
@SuppressWarnings("unchecked")
static Comparator super E> orNaturalOrder(
@Nullable Comparator super E> comparator) {
if (comparator != null) { // can't use ? : because of javac bug 5080917
return comparator;
}
return (Comparator) Ordering.natural();
}
/**
* Returns a sorted map containing the mappings in {@code unfiltered} whose
* keys satisfy a predicate. The returned map is a live view of {@code
* unfiltered}; changes to one affect the other.
*
* The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
* values()} views have iterators that don't support {@code remove()}, but all
* other methods are supported by the map and its views. When given a key that
* doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()}
* methods throw an {@link IllegalArgumentException}.
*
*
When methods such as {@code removeAll()} and {@code clear()} are called
* on the filtered map or its views, only mappings whose keys satisfy the
* filter will be removed from the underlying map.
*
*
The returned map isn't threadsafe or serializable, even if {@code
* unfiltered} is.
*
*
Many of the filtered map's methods, such as {@code size()},
* iterate across every key/value mapping in the underlying map and determine
* which satisfy the filter. When a live view is not needed, it may be
* faster to copy the filtered map and use the copy.
*
*
Warning: {@code keyPredicate} must be consistent with
* equals, as documented at {@link Predicate#apply}. Do not provide a
* predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
* inconsistent with equals.
*/
@GwtIncompatible("untested")
public static SortedMap filterKeys(
SortedMap unfiltered, final Predicate super K> keyPredicate) {
// TODO: Return a subclass of Maps.FilteredKeyMap for slightly better
// performance.
checkNotNull(keyPredicate);
Predicate> entryPredicate = new Predicate>() {
@Override
public boolean apply(Entry input) {
return keyPredicate.apply(input.getKey());
}
};
return filterEntries(unfiltered, entryPredicate);
}
/**
* Returns a sorted map containing the mappings in {@code unfiltered} whose
* values satisfy a predicate. The returned map is a live view of {@code
* unfiltered}; changes to one affect the other.
*
* The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
* values()} views have iterators that don't support {@code remove()}, but all
* other methods are supported by the map and its views. When given a value
* that doesn't satisfy the predicate, the map's {@code put()}, {@code
* putAll()}, and {@link Entry#setValue} methods throw an {@link
* IllegalArgumentException}.
*
*
When methods such as {@code removeAll()} and {@code clear()} are called
* on the filtered map or its views, only mappings whose values satisfy the
* filter will be removed from the underlying map.
*
*
The returned map isn't threadsafe or serializable, even if {@code
* unfiltered} is.
*
*
Many of the filtered map's methods, such as {@code size()},
* iterate across every key/value mapping in the underlying map and determine
* which satisfy the filter. When a live view is not needed, it may be
* faster to copy the filtered map and use the copy.
*
*
Warning: {@code valuePredicate} must be consistent with
* equals, as documented at {@link Predicate#apply}. Do not provide a
* predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
* inconsistent with equals.
*/
@GwtIncompatible("untested")
public static SortedMap filterValues(
SortedMap unfiltered, final Predicate super V> valuePredicate) {
checkNotNull(valuePredicate);
Predicate> entryPredicate =
new Predicate>() {
@Override
public boolean apply(Entry input) {
return valuePredicate.apply(input.getValue());
}
};
return filterEntries(unfiltered, entryPredicate);
}
/**
* Returns a sorted map containing the mappings in {@code unfiltered} that
* satisfy a predicate. The returned map is a live view of {@code unfiltered};
* changes to one affect the other.
*
* The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
* values()} views have iterators that don't support {@code remove()}, but all
* other methods are supported by the map and its views. When given a
* key/value pair that doesn't satisfy the predicate, the map's {@code put()}
* and {@code putAll()} methods throw an {@link IllegalArgumentException}.
* Similarly, the map's entries have a {@link Entry#setValue} method that
* throws an {@link IllegalArgumentException} when the existing key and the
* provided value don't satisfy the predicate.
*
*
When methods such as {@code removeAll()} and {@code clear()} are called
* on the filtered map or its views, only mappings that satisfy the filter
* will be removed from the underlying map.
*
*
The returned map isn't threadsafe or serializable, even if {@code
* unfiltered} is.
*
*
Many of the filtered map's methods, such as {@code size()},
* iterate across every key/value mapping in the underlying map and determine
* which satisfy the filter. When a live view is not needed, it may be
* faster to copy the filtered map and use the copy.
*
*
Warning: {@code entryPredicate} must be consistent with
* equals, as documented at {@link Predicate#apply}.
*/
@GwtIncompatible("untested")
public static SortedMap filterEntries(
SortedMap unfiltered,
Predicate super Entry> entryPredicate) {
checkNotNull(entryPredicate);
return (unfiltered instanceof FilteredSortedMap)
? filterFiltered((FilteredSortedMap) unfiltered, entryPredicate)
: new FilteredSortedMap(checkNotNull(unfiltered), entryPredicate);
}
/**
* Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
* filtering a filtered sorted map.
*/
private static SortedMap filterFiltered(
FilteredSortedMap map,
Predicate super Entry> entryPredicate) {
Predicate> predicate
= Predicates.and(map.predicate, entryPredicate);
return new FilteredSortedMap(map.sortedMap(), predicate);
}
private static class FilteredSortedMap
extends Maps.FilteredEntryMap implements SortedMap {
FilteredSortedMap(SortedMap unfiltered,
Predicate super Entry> entryPredicate) {
super(unfiltered, entryPredicate);
}
SortedMap sortedMap() {
return (SortedMap) unfiltered;
}
@Override public Comparator super K> comparator() {
return sortedMap().comparator();
}
@Override public K firstKey() {
// correctly throws NoSuchElementException when filtered map is empty.
return keySet().iterator().next();
}
@Override public K lastKey() {
SortedMap headMap = sortedMap();
while (true) {
// correctly throws NoSuchElementException when filtered map is empty.
K key = headMap.lastKey();
if (apply(key, unfiltered.get(key))) {
return key;
}
headMap = sortedMap().headMap(key);
}
}
@Override public SortedMap headMap(K toKey) {
return new FilteredSortedMap(sortedMap().headMap(toKey), predicate);
}
@Override public SortedMap subMap(K fromKey, K toKey) {
return new FilteredSortedMap(
sortedMap().subMap(fromKey, toKey), predicate);
}
@Override public SortedMap tailMap(K fromKey) {
return new FilteredSortedMap(
sortedMap().tailMap(fromKey), predicate);
}
}
}