Если есть предпочтение иметь Map
структуру данных, которая по своей природе сортирует по значениям без необходимости запуска каких-либо методов сортировки или явного перехода к служебной программе, то могут быть применимы следующие решения:
(1) org.drools.chance.core.util.ValueSortedMap (проект JBoss) поддерживает две внутренние карты: одну для поиска и одну для поддержки отсортированных значений. Очень похоже на ранее добавленные ответы, но, вероятно, именно абстракция и инкапсуляция (включая механизм копирования) делают его более безопасным для использования извне.
(2) http://techblog.molindo.at/2008/11/java-map-sorted-by-value.html избегает обслуживания двух карт и вместо этого использует / расширяет LinkedMap Apache Common. (Примечание автора блога: as all the code here is in the public domain
):
// required to access LinkEntry.before and LinkEntry.after
package org.apache.commons.collections.map;
// SNIP: imports
/**
* map implementation based on LinkedMap that maintains a sorted list of
* values for iteration
*/
public class ValueSortedHashMap extends LinkedMap {
private final boolean _asc;
// don't use super()!
public ValueSortedHashMap(final boolean asc) {
super(DEFAULT_CAPACITY);
_asc = asc;
}
// SNIP: some more constructors with initial capacity and the like
protected void addEntry(final HashEntry entry, final int hashIndex) {
final LinkEntry link = (LinkEntry) entry;
insertSorted(link);
data[hashIndex] = entry;
}
protected void updateEntry(final HashEntry entry, final Object newValue) {
entry.setValue(newValue);
final LinkEntry link = (LinkEntry) entry;
link.before.after = link.after;
link.after.before = link.before;
link.after = link.before = null;
insertSorted(link);
}
private void insertSorted(final LinkEntry link) {
LinkEntry cur = header;
// iterate whole list, could (should?) be replaced with quicksearch
// start at end to optimize speed for in-order insertions
while ((cur = cur.before) != header & amp; & amp; !insertAfter(cur, link)) {}
link.after = cur.after;
link.before = cur;
cur.after.before = link;
cur.after = link;
}
protected boolean insertAfter(final LinkEntry cur, final LinkEntry link) {
if (_asc) {
return ((Comparable) cur.getValue())
.compareTo((V) link.getValue()) & lt; = 0;
} else {
return ((Comparable) cur.getValue())
.compareTo((V) link.getValue()) & gt; = 0;
}
}
public boolean isAscending() {
return _asc;
}
}
(3) Напишите пользовательский Map
или расширение от LinkedHashMap
, которое будет сортировать только при перечислении (например, values()
, keyset()
, entryset()
) по мере необходимости. Внутренняя реализация / поведение абстрагируется от той, которая использует этот класс, но клиенту этого класса кажется, что значения всегда сортируются при запросе перечисления. Этот класс надеется, что сортировка произойдет в основном один раз, если все операции put
были завершены до перечисления. Метод сортировки принимает некоторые из предыдущих ответов на этот вопрос.
public class SortByValueMap<K, V> implements Map<K, V> {
private boolean isSortingNeeded = false;
private final Map<K, V> map = new LinkedHashMap<>();
@Override
public V put(K key, V value) {
isSortingNeeded = true;
return map.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
isSortingNeeded = true;
map.putAll(map);
}
@Override
public Set<K> keySet() {
sort();
return map.keySet();
}
@Override
public Set<Entry<K, V>> entrySet() {
sort();
return map.entrySet();
}
@Override
public Collection<V> values() {
sort();
return map.values();
}
private void sort() {
if (!isSortingNeeded) {
return;
}
List<Entry<K, V>> list = new ArrayList<>(size());
for (Iterator<Map.Entry<K, V>> it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry<K, V> entry = it.next();
list.add(entry);
it.remove();
}
Collections.sort(list);
for (Entry<K, V> entry : list) {
map.put(entry.getKey(), entry.getValue());
}
isSortingNeeded = false;
}
@Override
public String toString() {
sort();
return map.toString();
}
}
(4) Гуава предлагает ImmutableMap.Builder.orderEntriesByValue (Comparator valueComparator) , хотя полученная карта будет неизменной:
Конфигурирует этого Builder для упорядочения записей по значению в соответствии с
указанный компаратор.
Порядок сортировки стабилен, то есть если две записи имеют значения, которые
сравните как эквивалент, запись, которая была вставлена первой, будет первой
в порядке итерации построенной карты.