带有比较器的 TreeMap 比较键中字符串的长度
TreeMap with comparator comparing length of string in keys
我需要一个使用字符串长度作为排序标准的 TreeMap 将字符串映射到整数。这是我的代码:
TreeMap<String, Integer> map = new TreeMap<>(Comparator.comparingInt(String::length)) {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
我希望地图的内容是这样的:
{one=1, two=2, six=6, four=4, five=5, three=3}
但我得到的是:
{one=6, four=5, three=3}
查看TreeMap的put
方法的代码,可以看出,如果定义了Comparator,则使用比较器返回的值来决定是否创建一个新的key地图,或覆盖现有地图的值。在我的例子中,因为我有三个长度为 3 的键(“一”、“二”和“六”),它只插入一个长度为 3 的键(第一个插入的键,“一个”)并更新它的值(第一个 1 ,然后是 2,最后是 6)。长度为 4 的密钥(“四”和“五”)也是如此。
如何让树图插入我定义的所有键(“一”、“二”、“三”、“四”、“五”、“六”)按键的长度排序?
您需要一个双重比较器,首先比较字符串长度,然后比较字符串本身。喜欢:
public class MyTreeMapComparator implements Comparator<String> {
public int compare(String one, String two) {
if (one.length() == two.length()) {
return one.compareTo(two);
} else return two.length() - one.length();
}
}
指定的顺序{one=1, two=2, six=6, four=4, five=5, three=3}
不能用TreeMap
实现,因为这个实现只能按键排序,一旦键的长度有多次冲突,额外的比较器需要值。
因此,可以先创建原始地图,然后可以使用 Stream API Stream::sorted
和 Collectors.toMap
以自定义顺序对其 entrySet
进行排序:
- 按密钥长度(升序)
- 按值(升序)
然后将结果收集到一个LinkedHashMap
维护插入顺序的著名的:
Map<String, Integer> raw = new HashMap<>() {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
Map<String, Integer> map = raw.entrySet()
.stream()
.sorted(Comparator.<Map.Entry<String, Integer>>comparingInt(e -> e.getKey().length())
.thenComparingInt(Map.Entry::getValue))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(a, b) -> a,
LinkedHashMap::new
));
System.out.println(map);
输出:
{one=1, two=2, six=6, four=4, five=5, three=3}
更新
对于给定的输入,似乎可以为 TreeMap
维护插入顺序提供自定义比较器:
Map<String, Integer> map2 = new TreeMap<>(
Comparator.comparingInt(String::length)
.thenComparing((k1, k2) -> 1) // pick the "earlier" key of the two
) {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
System.out.println(map2);
输出:
{one=1, two=2, six=6, four=4, five=5, three=3}
我需要一个使用字符串长度作为排序标准的 TreeMap 将字符串映射到整数。这是我的代码:
TreeMap<String, Integer> map = new TreeMap<>(Comparator.comparingInt(String::length)) {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
我希望地图的内容是这样的:
{one=1, two=2, six=6, four=4, five=5, three=3}
但我得到的是:
{one=6, four=5, three=3}
查看TreeMap的put
方法的代码,可以看出,如果定义了Comparator,则使用比较器返回的值来决定是否创建一个新的key地图,或覆盖现有地图的值。在我的例子中,因为我有三个长度为 3 的键(“一”、“二”和“六”),它只插入一个长度为 3 的键(第一个插入的键,“一个”)并更新它的值(第一个 1 ,然后是 2,最后是 6)。长度为 4 的密钥(“四”和“五”)也是如此。
如何让树图插入我定义的所有键(“一”、“二”、“三”、“四”、“五”、“六”)按键的长度排序?
您需要一个双重比较器,首先比较字符串长度,然后比较字符串本身。喜欢:
public class MyTreeMapComparator implements Comparator<String> {
public int compare(String one, String two) {
if (one.length() == two.length()) {
return one.compareTo(two);
} else return two.length() - one.length();
}
}
指定的顺序{one=1, two=2, six=6, four=4, five=5, three=3}
不能用TreeMap
实现,因为这个实现只能按键排序,一旦键的长度有多次冲突,额外的比较器需要值。
因此,可以先创建原始地图,然后可以使用 Stream API Stream::sorted
和 Collectors.toMap
以自定义顺序对其 entrySet
进行排序:
- 按密钥长度(升序)
- 按值(升序)
然后将结果收集到一个LinkedHashMap
维护插入顺序的著名的:
Map<String, Integer> raw = new HashMap<>() {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
Map<String, Integer> map = raw.entrySet()
.stream()
.sorted(Comparator.<Map.Entry<String, Integer>>comparingInt(e -> e.getKey().length())
.thenComparingInt(Map.Entry::getValue))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(a, b) -> a,
LinkedHashMap::new
));
System.out.println(map);
输出:
{one=1, two=2, six=6, four=4, five=5, three=3}
更新
对于给定的输入,似乎可以为 TreeMap
维护插入顺序提供自定义比较器:
Map<String, Integer> map2 = new TreeMap<>(
Comparator.comparingInt(String::length)
.thenComparing((k1, k2) -> 1) // pick the "earlier" key of the two
) {{
put("one", 1);
put("two", 2);
put("three", 3);
put("four", 4);
put("five", 5);
put("six", 6);
}};
System.out.println(map2);
输出:
{one=1, two=2, six=6, four=4, five=5, three=3}