如何在Java Stream中按值降序对LinkedHashMap进行排序?

16

按升序排序,我可以使用:

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

我该如何按降序排序?

4个回答

43

要以相反的顺序排序,将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
        ));

这个答案是唯一有效的。 - Grzegorz Piwowarek
谢谢,我不知道我可以使用这个Comparator.reverserOrder()。 事实上,我认为会有一种直接的方法来做到这一点,比如.sorted(Map.Entry.comparingByValueReverse()) - Oxydron

6
您可以传递任何您希望的比较器到comparingByValue中。
例如(我希望语法正确,因为我无法测试):
myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((v1,v2)->v2.compareTo(v1)))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

通过使用自然排序 (ComparablecompareTo) 反向比较两个相反顺序的条目的值,你将获得一个与 comparingByValue() 相反的顺序(该方法等同于 comparingByValue((v1,v2)->v1.compareTo(v2)))。

顺便提一下,我不确定 Collectors.toMap 是否返回一个 LinkedHashMap 实例,即使它目前确实是这样,由于 Javadoc 没有提到这点,所以你不能依赖它。

为了确保生成的 Map 是一个 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));

1
正如其名称所示(comparingByValue),lambda表达式的类型参数是V而不是Entry<K,V>,因为您提供了一个比较器来比较值,所以您可以将其更改为comparingByValue((v1, v2)->v2.compareTo(v1))或者更好地使用comparingByValue(reverseOrder()),就像@Misha建议的那样... - Alexis C.
正如你所说,快速查看toMap的源代码,你会发现它返回toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new)。因此,基本上你的实现不会做什么有用的事情(尽管你是从OP的问题中获取的)。 - Alexis C.
1
@AlexisC,感谢您的评论。我完全忽略了那个问题。这就是当我编写代码而不尝试编译它时会发生的事情。 - Eran

3

Stream有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),它会返回一个收集器,该收集器可以将元素累积到Map中,其中键和值是将提供的映射函数应用于输入元素的结果。

工作代码

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)
                                           )
                );           
     }


}

0

自从Java 1.8以来,java.util.Comparator.reversed()

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

1
这不正确;应该是Map.Entry.comparingByValue(Comparator.reverseOrder()))。 - johnlemon
无法编译 - b15
这将无法编译。 - Jitendra Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接