在Java8中比较By Value返回奇怪的结果

use*_*328 2 java dictionary java-8

我正在尝试根据值对地图进行排序.

但我看到以下程序有一些奇怪的行为

public class CompareByValueMain {

    public static void main(String[] args) {
        Map<String,Integer> itemIDToTimeMap = new HashMap<String,Integer>();

        itemIDToTimeMap.put("Baggage", 3);
        itemIDToTimeMap.put("Handbag", 16);
        itemIDToTimeMap.put("Closed Footwear", 4);
        itemIDToTimeMap.put("Shirt", 25);

        Set<String> itemIDs = itemIDToTimeMap.entrySet().stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());

        System.out.println(itemIDs);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出结果是正确的

[衬衫,手提包,封闭式鞋类,行李 ]

但是当我从Baggage改为Bag时的输入 它给出了以下输出

[衬衫,,手提包,封闭式鞋]

理想情况下,应根据地图中的值进行排序,而不管键值如何.但是如果在这里更改密钥,不确定为什么会改变.

sla*_*dan 8

您正在将结果收集到一个Set.并非所有Set的保证订单.

所以排序工作正常,但之后它存储在一个不打扰字符串顺序的容器中.

List<>排序完成后,使用类似于存储数据的容器.这将保证您的商品的订单.

public class CompareByValueMain {

    public static void main(String[] args) {
        Map<String,Integer> itemIDToTimeMap = new HashMap<String,Integer>();

        itemIDToTimeMap.put("Bag", 3); // already changed to "Bag" to demonstrate the working code
        itemIDToTimeMap.put("Handbag", 16);
        itemIDToTimeMap.put("Closed Footwear", 4);
        itemIDToTimeMap.put("Shirt", 25);

        List<String> itemIDs = // use List<> instead of Set<>
                itemIDToTimeMap.entrySet().stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList()); // use .toList() instead of .toSet()

        System.out.println(itemIDs);
    }
}
Run Code Online (Sandbox Code Playgroud)

一个简单的例子来证明差异:

public static void main(String[] args) {
    System.out.println("List:");
    Stream
        .of("b", "a")
        .collect(Collectors.toList())
        .stream()
        .forEach(System.out::println);

    System.out.println();
    System.out.println("Set:");
    Stream
        .of("b", "a")
        .collect(Collectors.toSet())
        .stream()
        .forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

List:
b
a

Set:
a
b
Run Code Online (Sandbox Code Playgroud)


Psh*_*emo 6

问题在这里:

.collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)

因为没有排序的Collectors.toSet()退货HashSet(因为在大多数情况下我们并不真正需要套装中的订单,而是提供其contains方法的速度HashSet).

使用LinkedHashSet,如果你想保留插入顺序

.collect(Collectors.toCollection(LinkedHashSet::new));
Run Code Online (Sandbox Code Playgroud)

或者取决于你想如何使用这个结果可能使用List而不是?