Как отсортировать LinkedHashMap по значению в порядке убывания в потоке java?

Чтобы отсортировать его по возрастанию, я могу использовать:

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Как я могу сделать это в порядке убывания?

Ответ 1

Так как Java 1.8 java.util.Comparator.reversed()

myMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue().reversed())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Ответ 2

Чтобы отсортировать в обратном порядке, передайте Comparator.reverseOrder() как параметр в comparingByValue.

Чтобы получить LinkedHashMap, вы должны запросить его с помощью 4-аргумента toMap(). Если вы не укажете, какую карту вы хотите, вы получите то, что по умолчанию, которое в настоящее время является HashMap. Поскольку HashMap не сохраняет порядок элементов, он определенно не сделает для вас.

myMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        .collect(Collectors.toMap(
                Map.Entry::getKey, 
                Map.Entry::getValue, 
                (x,y)-> {throw new AssertionError();},
                LinkedHashMap::new
        ));

Со статическим импортом становится немного приятнее:

myMap.entrySet().stream()
        .sorted(comparingByValue(reverseOrder()))
        .collect(toMap(
                Map.Entry::getKey, 
                Map.Entry::getValue, 
                (x,y)-> {throw new AssertionError();},
                LinkedHashMap::new
        ));

Ответ 3

Вы можете передать любой компаратор, который вы хотите comparingByValue.

Например (надеюсь, что я получил синтаксис правильно, поскольку я не могу его проверить):

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((v1,v2)->v2.compareTo(v1)))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Сравнивая значения двух записей в обратном порядке, используя естественный порядок (Comparable compareTo), вы получите обратный порядок по сравнению с тем, что comparingByValue() (что эквивалентно comparingByValue((v1,v2)->v1.compareTo(v2))) будет дайте вам.

Кстати, я не уверен, что Collectors.toMap возвращает экземпляр LinkedHashMap, и даже если он в настоящее время работает, он может измениться в будущем, поскольку Javadoc не упоминает об этом, поэтому вы не можете положиться на нем.

Чтобы убедиться, что результирующая Карта будет LinkedHashMap, вы должны использовать другой вариант toMap:

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((v1,v2)->v2.compareTo(v1)))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1,v2)->v1, LinkedHashMap::new));

Ответ 4

Поток имеет метод sorted, который принимает компаратор, поэтому вы можете напрямую использовать компаратор как (x,y)->y.getKey().compareTo(x.getKey()) для сортировки по убыванию. Чтобы отсортировать карту по возрастанию, мы можем отменить порядок как (x,y)->x.getKey().compareTo(y.getKey())

для консолидации результата в LinkedHashMap мы можем использовать Collectors toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier), который Возвращает коллекционер, который накапливает элементы в карту, ключи и значения которой являются результатом применения предоставленных функций отображения к входным элементам.

Рабочий код

import java.io.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class HelloWorld{

     public static void main(String []args){
        LinkedHashMap<Integer,Integer> hashMap = new LinkedHashMap<Integer,Integer>(); 
            hashMap.put(1,5);
            hashMap.put(7,9);
            hashMap.put(3,8);
            hashMap.put(10,5);

            Function<Map.Entry<Integer,Integer>,Integer> keyMapper = x->x.getKey();
            Function<Map.Entry<Integer,Integer>,Integer> valueMapper = x->x.getValue();
            BinaryOperator< Integer> mergeFunction = (x,y)->x;// we do not want any merging here 
            Supplier<LinkedHashMap<Integer,Integer>> mapRequired =()-> {return new LinkedHashMap<Integer,Integer>();};// to maintain order we must use LinkedHashMap
            Comparator<Map.Entry<Integer,Integer>> descendingComparator = (x,y)->y.getKey().compareTo(x.getKey());
            // we can write it as  

        System.out.println(
                  hashMap.entrySet().stream()
                             .sorted (descendingComparator) 
                             .collect(Collectors.toMap(
                                                      keyMapper,
                                                       valueMapper,
                                                       mergeFunction,
                                                       mapRequired)
                                           )
                );           

// or even by writing below will also work

        System.out.println(
                  hashMap.entrySet().stream()
                             .sorted ((x,y)->y.getKey().compareTo(x.getKey())) 
                             .collect(Collectors.toMap(
                                                       x->x.getKey(),
                                                       x->x.getValue(),
                                                       (x,y)->x,
                                                       LinkedHashMap::new)
                                           )
                );           
     }


}