Три відповіді на 1 рядок ...
Я би використовував Google Collections Guava для цього - якщо ваші цінності, Comparable
то ви можете використовувати
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Який створить функцію (об'єкт) для карти [, яка приймає будь-яку з клавіш як вхідну, повертаючи відповідне значення], а потім застосує до них природне (порівнянне) впорядкування [значення].
Якщо вони не порівнянні, вам потрібно буде щось робити за принципом
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
Вони можуть бути застосовані до TreeMap (як Ordering
розширення Comparator
) або LinkedHashMap після деякого сортування
Примітка : Якщо ви збираєтесь використовувати TreeMap, пам’ятайте, що якщо порівняння == 0, то цей пункт вже є у списку (що станеться, якщо у вас є кілька значень, що порівнюють одне і те ж). Щоб полегшити це, ви можете додати свій ключ до компаратора так (припускаючи, що ваші ключі та значення Comparable
):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Застосувати природне впорядкування до значення, відображеного ключем, і з'єднати його з природним упорядкуванням ключа
Зверніть увагу , що це буде по- , як і раніше не працює , якщо ключі порівнювати 0, але це повинно бути досить для більшості comparable
елементів (як hashCode
, equals
і compareTo
часто синхронізовані ...)
Див. Замовлення.onResultOf () та Functions.forMap () .
Впровадження
Отже, коли у нас є компаратор, який робить те, що ми хочемо, нам потрібно отримати результат.
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Зараз це, швидше за все, спрацює, але:
- потрібно зробити, маючи повну готову карту
- Не намагайтеся порівняти вище на а
TreeMap
; немає сенсу намагатися порівнювати вставлений ключ, коли він не має значення, поки не буде поставлено, тобто він зламається дуже швидко
Точка 1 для мене є дещо розривом угоди; Колекції google неймовірно ліниві (що добре: ви можете виконати майже кожну операцію за мить; справжня робота робиться, коли ви починаєте використовувати результат), і для цього потрібно скопіювати цілу карту!
"Повна" відповідь / Жива відсортована карта за значеннями
Не хвилюйтесь, хоча; якщо ви були достатньо одержимі тим, що "жива" карта впорядкована таким чином, ви могли б вирішити не одну, а обидві (!) вищезазначених питань чимось божевільним, як це:
Примітка. Це значно змінилося в червні 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 для сортування. Але перед цим ми перевіряємо хеш-карту, щоб побачити, що ключ насправді не є дублікатом. Крім того, створений нами компаратор також міститиме ключ, щоб дублюючі значення не видаляли не повторювані ключі (через порівняння ==). Ці два пункти життєво важливі для забезпечення збереження контракту на карту; якщо ви думаєте, що цього не хочете, ви майже перебуваєте в точці повернення карти повністю (до Map<V,K>
).
Конструктор повинен бути названий як
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
іCollections.sort ....
саме так.