Я хочу написать компаратор, который позволит мне сортировать TreeMap по значению вместо естественного упорядочения по умолчанию.
Я пробовал что-то вроде этого, но не могу узнать, что пошло не так:
import java.util.*;
class treeMap {
public static void main(String[] args) {
System.out.println("the main");
byValue cmp = new byValue();
Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
for (Map.Entry<String,Integer> pair: map.entrySet()) {
System.out.println(pair.getKey()+":"+pair.getValue());
}
}
}
class byValue implements Comparator<Map.Entry<String,Integer>> {
public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
if (e1.getValue() < e2.getValue()){
return 1;
} else if (e1.getValue() == e2.getValue()) {
return 0;
} else {
return -1;
}
}
}
Я думаю, что я спрашиваю: могу ли я Map.Entry
передать в компаратор?
Ответы:
Вы не можете
TreeMap
самостоятельно сортировать значения, так как это не поддаетсяSortedMap
спецификации:Однако, используя внешнюю коллекцию, вы всегда можете отсортировать по
Map.entrySet()
своему усмотрению, либо по ключам, значениям или даже по комбинации (!!) двух.Вот общий метод , который возвращает
SortedSet
изMap.Entry
, учитывая ,Map
чьи ценностиComparable
:Теперь вы можете сделать следующее:
Обратите внимание, что прикольные вещи произойдут, если вы попытаетесь изменить либо
SortedSet
сам, либоMap.Entry
внутри, потому что это больше не «вид» оригинальной карты, какentrySet()
есть.Вообще говоря, необходимость сортировать записи карты по ее значениям нетипична.
Обратите внимание на
==
дляInteger
Ваш оригинальный компаратор сравнивает,
Integer
используя==
. Это почти всегда неправильно, так как==
сInteger
операндами является ссылочное равенство, а не равенство значений.Смежные вопросы
new Integer(i) == i
в Java? (ДА!!!)источник
ответ на полигенные смазки почти идеален. Хотя есть одна важная ошибка. Он не будет обрабатывать записи карты, где значения одинаковы.
Этот код: ...
Будет вывод:
Обратите внимание, как исчезла наша корова, когда она поделилась значением «1» с нашей обезьяной: O!
Эта модификация кода решает эту проблему:
источник
Set
реализации содержат элемент более одного раза. Вы только что нарушили это ограничение. ИзSortedSet
API: Обратите внимание , что порядок поддерживается отсортированным набор должен быть согласован с равными ... . Решение было бы перейти кList
реализации.Set
с здесь. Так какComparator
нарушаетSet
договорSet.remove
иSet.contains
т. Д. Не работает ! Проверьте этот пример на ideone .int res= e1.getValue().compareTo(e2.getValue());
вint res= e2.getValue().compareTo(e1.getValue());
, у вас будет порядок убывания значений вместо возрастания.res != 0 ? res : e1.getKey().compareTo(e2.getKey())
чтобы сохранить порядок ключей с одинаковыми значениями.В Java 8:
источник
TreeMap
Будет всегда отсортирован по клавишам, все остальное невозможно.Comparator
Просто позволяет контролировать , как ключи сортируются.Если вы хотите отсортированные значения, вы должны извлечь их в
List
и отсортировать.источник
Это не может быть сделано с помощью a
Comparator
, так как он всегда получит ключ карты для сравнения.TreeMap
сортировать можно только по ключу.источник
SortedMap
которой указана сортировка по ключам) beginnersbook.com/2014/07/…Comparator
использует существующую карту для сортировки значений. Другими словами, он не может сортировать произвольные значения, введенныеTreeMap
позже, только значения, которые уже есть в исходной карте.Ответ Олофа хорош, но для совершенства нужна еще одна вещь. В комментариях под своим ответом dacwe (правильно) указывает, что его реализация нарушает контракт Сравнения / Равного для Наборов. Если вы попытаетесь вызвать, содержит или удаляет запись, которая явно находится в наборе, набор не распознает ее из-за кода, позволяющего размещать записи с равными значениями в наборе. Итак, чтобы это исправить, нам нужно проверить равенство ключей:
«Обратите внимание, что порядок, поддерживаемый отсортированным набором (независимо от того, предоставлен или нет явный компаратор), должен соответствовать равенствам, если отсортированный набор должен правильно реализовывать интерфейс Set ... интерфейс Set определяется в терминах операции equals , но отсортированный набор выполняет все сравнения элементов, используя свой метод CompareTo (или сравнение), поэтому два элемента, которые считаются равными с помощью этого метода, с точки зрения отсортированного набора равны ". ( http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html )
Поскольку мы изначально упустили равенство, чтобы заставить набор добавлять записи с равными значениями, теперь мы должны проверить равенство в ключах, чтобы набор фактически возвращал искомую запись. Это немного грязно и определенно не так, как наборы были предназначены для использования - но это работает.
источник
Я знаю, что этот пост специально просит сортировать TreeMap по значениям, но для тех из нас, кто на самом деле не заботится о реализации, но хочет решение, которое сохраняет сортировку коллекции по мере добавления элементов, я был бы признателен за отзыв об этом на основе TreeSet решение. С одной стороны, элементы нелегко получить по ключу, но для имеющегося у меня варианта использования (поиск n ключей с наименьшими значениями) это не было требованием.
источник
Многие люди слышат совет использовать List, и я предпочитаю использовать его
Вот два метода, которые вам нужно отсортировать записи карты в соответствии с их значениями.
источник