Как сделать сортировку map по значениям и по ключам
Делаю программу для подсчёта слов в файле. Сделал сортировку по значениям:
Map<String, Integer> treeMap = new TreeMap<String, Integer>(wordCount);
MyComparator comparator = new MyComparator(wordCount);
Map<String, Integer> newMap = new TreeMap<>(comparator);
newMap.putAll(wordCount);
создал класс который делает сортировку по значениям:
class MyComparator implements Comparator<Object> {
Map<String, Integer> map;
public MyComparator(Map<String, Integer> map) {
this.map = map;
}
public int compare(Object o1, Object o2) {
if (map.get(o2) == map.get(o1))
return 1;
else
return ((Integer) map.get(o2)).compareTo((Integer)
map.get(o1));
}
}
и при выходе получается:
наше = 20
пушкин = 20
тигруля = 18
полете = 18
игрив=16
котенок=16
манул=12
красив=12
а мне нужно чтоб все ключи с одинаковыми значениями были в алфавитном порядке. Без использования lambda, stream.
И еще если кто то может подсказать как из Map<String, Integer> newMap сделать String который возвращал бы значения в следующем порядке:
наше - 20
пушкин - 20
полете - 18
тигруля - 18
игрив - 16
котенок - 16
красив - 12
манул - 12
Я думал разделить ключи и значения в 2 разных листа и с помощью toString() сделать этот формат. Может есть более лёхкие пути.
Ответы (1 шт):
Конструктор TreeMap(Comparator<? super K> comparator) принимает компаратор для типа ключа, а не для другого экземпляра Map или Map.Entry!
Если используется TreeMap<String, Integer>, то элементы этой карты уже будут отсортированы по значению ключей в алфавитном порядке, и более лёгким путём будет отсортировать поток элементов карты, которые являются Map.Entry<String, Integer>:
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.forEach(e -> System.out.println(e.getKey() + " - " + e.getValue()));
Для получения строки достаточно использовать коллектор Collectors.joining, как было показано в предыдущем ответе:
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.collect(Collectors.joining("\n", e -> e.getKey() + " - " + e.getValue()));
Если нет возможностей использовать Stream API, то всё равно придётся преобразовать entrySet карты частоты слов в другую сортируемую коллекцию (тот же список), и сортировать уже его:
List<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
entries.sort(new MyComparator());
Компаратор MyComparator без лямбд:
class MyComparator implements Comparator<Map.Entry<String, Integer>> {
@Override
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
int reverseValueCompared = Integer.compare(e2.getValue(), e1.getValue());
if (reverseValueCompared == 0) {
return e1.getKey().compareTo(e2.getKey());
}
return reverseValueCompared;
}
}
Для преобразования в строку к сожалению не получится использовать String.join, поэтому придётся написать метод для конвертации:
static <K, V> String stats(Collection<Map.Entry<K, V>> entries) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<K, V> e : entries) {
if (sb.length() > 0) sb.append("\n");
sb.append(e.getKey()).append(" - ").append(e.getValue());
}
return sb.toString();
}
System.out.println(stats(entries));