[英]Unexpected behavior when using Comparator.comparing(HashMap::get) as a comparator
Doing the exercise 'Literature' onhttps://java-programming.mooc.fi/part-10/2-interface-comparable I discovered a very strange behavior when trying to sort key-value pairs in a HashMap, without copying anything to a TreeMap.在https://java-programming.mooc.fi/part-10/2-interface-comparable上进行“文学”练习时,我在尝试对 HashMap 中的键值对进行排序时发现了一个非常奇怪的行为,而没有将任何内容复制到树状图。 I was supposed to add books, by making a Book class and adding them to a List.
我应该通过制作一本书 class 并将它们添加到列表中来添加书籍。 However I wanted to try without making a new class, so opted for the HashMap.
但是我想尝试不制作新的 class,所以选择了 HashMap。 My code was as follows:
我的代码如下:
public class MainProgram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Map<String, Integer> bookshelf = new HashMap<>();
while (true) {
System.out.println("Input the name of the book, empty stops: ");
String bookName = scanner.nextLine();
if (bookName.equals("")) {
break;
}
System.out.println("Input the age recommendation: ");
int age = Integer.valueOf(scanner.nextLine());
bookshelf.put(bookName, age);
}
System.out.println(bookshelf.size() + " book" + (bookshelf.size() > 1 ? "s" : "") + " in total.");
System.out.println("Books:");
bookshelf.keySet().stream().sorted(Comparator.comparing(bookshelf::get)).forEach((key) -> System.out.println(key + " (recommended for " + bookshelf.get(key) + " year-olds or older)"));
}
}
using .sorted(Comparator.comparing(bookshelf::get))
was my idea of sorting them by the recommended age, which worked.使用
.sorted(Comparator.comparing(bookshelf::get))
是我按照推荐的年龄对它们进行排序的想法,这很有效。
However, there exists an unexpected behavior that when the book's name is a single character ("A","b"), the program would also sort the keys alphabetically as though i made a comparator like Comparator.comparing(bookshelf::get).thenComparing(/*keys in keyset*/)
but would sometimes also sort like aAbB
但是,存在一种意外行为,即当书名是单个字符(“A”、“b”)时,程序还会按字母顺序对键进行排序,就好像我做了一个比较器,比如
Comparator.comparing(bookshelf::get).thenComparing(/*keys in keyset*/)
但有时也会像aAbB
一样排序
AA bb give unsorted results
AAA bbb give semi-sorted results in one or two buckets
AAAA bbbb give semi- or completely sorted results
AAAAA bbbbb and onward give unsorted results.
Can anybody explain what is happening here, at compiler level or somehow let me make sense of this?任何人都可以解释这里发生了什么,在编译器级别或以某种方式让我理解这一点吗?
bookshelf.keySet().stream().sorted(Comparator.comparing(bookshelf::get))
From the above snippet in your example, we can see that you're trying to sort the keys of bookshelf
by their respective value.从您示例中的上述代码段中,我们可以看到您正在尝试按各自的值对
bookshelf
的键进行排序。
The issue with this is that two book names could be mapped to the same age recommendation.这样做的问题是两个书名可以映射到相同的年龄推荐。 Because you only have a single
Comparator
and because HashMap
does not specify a consistent ordering, you have a chance at ending up with different results for the same inputs.因为您只有一个
Comparator
器,并且因为HashMap
没有指定一致的排序,所以您有机会最终获得相同输入的不同结果。
To ameliorate this, you can use thenComparing
to handle the case when duplicate value-mappings are encountered:为了改善这种情况,您可以使用
thenComparing
来处理遇到重复值映射的情况:
bookshelf.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
.forEach(entry -> System.out.println(entry.getKey() + " (recommended for " + entry.getValue() + " year-olds or older)"));
Build the Comparator of Entry and use Entry::getValue
and Entry::getKey
to sort by value then by key构建 Entry 的 Comparator 并使用
Entry::getValue
和Entry::getKey
按值排序,然后按键排序
Comparator<Entry<String, Integer>> cmp = Comparator.comparing(Entry::getValue);
bookshelf.entrySet()
.stream()
.sorted(cmp.thenComparing(Entry::getKey))
.forEach(entry -> System.out.println(entry.getKey() + " (recommended for " + entry.getValue() + " year-olds or older)"));
This is happening since you are only using "key" to compare.发生这种情况是因为您仅使用“键”进行比较。 You should compare them by both "key" and "value".
您应该通过“键”和“值”来比较它们。 This should work fine:
这应该可以正常工作:
bookshelf.entrySet()
.stream()
.sorted(Map.Entry.<String,Integer>comparingByValue()
.thenComparing(Map.Entry.comparingByKey()))
.map(e -> e.getKey())
.forEach((key) -> System.out.println(key + " (recommended for " + bookshelf.get(key) + " year-olds or older)"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.