Три однострочных ответа ...
Я бы использовал Google Collections Guava для этого - если ваши значения, Comparable
то вы можете использовать
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Который создаст функцию (объект) для карты [которая принимает любую из клавиш в качестве входных данных, возвращая соответствующее значение], а затем применяет естественное (сопоставимое) упорядочение к ним [значениям].
Если они несопоставимы, то вам нужно сделать что-то вроде
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
Они могут быть применены к TreeMap (как Ordering
расширяет Comparator
) или LinkedHashMap после некоторой сортировки
NB . Если вы собираетесь использовать TreeMap, помните, что если сравнение == 0, то элемент уже находится в списке (что произойдет, если у вас есть несколько значений, которые сравнивают одно и то же). Чтобы облегчить это, вы можете добавить свой ключ к компаратору следующим образом (при условии, что ваши ключи и значения Comparable
):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Применить естественное упорядочение к значению, отображаемому ключом, и составить его с естественным упорядочением ключа
Обратите внимание, что это все равно не будет работать, если ваши ключи сравниваются с 0, но этого должно быть достаточно для большинства comparable
элементов (как hashCode
, equals
и compareTo
часто синхронизируются ...)
Смотрите Ordering.onResultOf () и Functions.forMap () .
Реализация
Итак, теперь, когда у нас есть компаратор, который делает то, что мы хотим, нам нужно получить от него результат.
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Теперь это, скорее всего, будет работать, но:
- должно быть сделано с учетом полной готовой карты
- Не пытайтесь сравнивать выше на a
TreeMap
; нет смысла пытаться сравнивать вставленный ключ, когда он не имеет значения, до окончания операции, т. е. он очень быстро сломается
Пункт 1 для меня немного нарушает условия сделки; Коллекции Google невероятно ленивы (и это хорошо: вы можете выполнять практически все операции за один раз; настоящая работа выполняется, когда вы начинаете использовать результат), а для этого нужно скопировать всю карту!
«Полный» ответ / Live отсортированная карта по значениям
Не волнуйтесь, хотя; если вы были достаточно одержимы сортировкой «живой» карты таким образом, вы могли бы решить не одну, а обе (!) из вышеуказанных проблем с помощью чего-то сумасшедшего, например:
Примечание. Это значительно изменилось в июне 2012 года - предыдущий код никогда не работал: требуется внутренний HashMap для поиска значений без создания бесконечного цикла между TreeMap.get()
-> compare()
и compare()
->get()
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
//A map for doing lookups on the keys for comparison so we don't get infinite loops
private final Map<K, V> valueMap;
ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
this(partialValueOrdering, new HashMap<K,V>());
}
private ValueComparableMap(Ordering<? super V> partialValueOrdering,
HashMap<K, V> valueMap) {
super(partialValueOrdering //Apply the value ordering
.onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
.compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
this.valueMap = valueMap;
}
public V put(K k, V v) {
if (valueMap.containsKey(k)){
//remove the key in the sorted set before adding the key again
remove(k);
}
valueMap.put(k,v); //To get "real" unsorted values for the comparator
return super.put(k, v); //Put it in value order
}
public static void main(String[] args){
TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
map.put("a", 5);
map.put("b", 1);
map.put("c", 3);
assertEquals("b",map.firstKey());
assertEquals("a",map.lastKey());
map.put("d",0);
assertEquals("d",map.firstKey());
//ensure it's still a map (by overwriting a key, but with a new value)
map.put("d", 2);
assertEquals("b", map.firstKey());
//Ensure multiple values do not clobber keys
map.put("e", 2);
assertEquals(5, map.size());
assertEquals(2, (int) map.get("e"));
assertEquals(2, (int) map.get("d"));
}
}
Когда мы помещаем, мы гарантируем, что хэш-карта имеет значение для компаратора, а затем помещаем его в TreeSet для сортировки. Но перед этим мы проверяем хеш-карту, чтобы увидеть, что ключ на самом деле не является дубликатом. Кроме того, созданный нами компаратор также будет включать ключ, чтобы дублированные значения не удаляли неповторяющиеся ключи (из-за сравнения ==). Эти 2 пункта жизненно важны для обеспечения соблюдения контракта карты; если вы думаете, что не хотите этого, то вы почти полностью изменили картуMap<V,K>
.
Конструктор должен быть вызван как
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
иCollections.sort ....
так.