英文:
how to sort map based on key length
问题
我有这个地图:
Map<String, String> unsortMap = new HashMap<String, String>();
unsortMap.put("./cq:dialog/content/items/tabs/items/tab1/items/columns/items", "40");
unsortMap.put("./cq:dialog/content", "80");
unsortMap.put("./cq:dialog", "75");
unsortMap.put("./cq:dialog/content/items/tabs/items/tab2/items/columns/items", "40");
unsortMap.put("./cq:dialog/content/sling:resourcetype", "granite/ui/components/coral/foundation/container");
我想根据键的长度对其进行排序,例如,如果键的“/”数量较少,则它将位于顶部。
期望的输出:
./cq:dialog
./cq:dialog/content/
./cq:dialog/content/sling:resourcetype
./cq:dialog/content/items/tabs/items/tab1/items/columns/items
./cq:dialog/content/items/tabs/items/tab2/items/columns/items
为此,我写了以下代码:
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted((entry1, entry2) -> {
int slashes1 = entry1.getKey().length() - entry1.getKey().replace("/", "").length();
int slashes2 = entry2.getKey().length() - entry2.getKey().replace("/", "").length();
return Integer.compare(slashes1, slashes2);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
这样做是因为它会基于“/”的数量进行比较。我尝试了自定义比较器,但没有获得预期的结果。
英文:
I have this map:
Map < String, String > unsortMap = new HashMap < String, String > ();
unsortMap.put("./cq:dialog/content/items/tabs/items/tab1/items/columns/items", "40");
unsortMap.put("./cq:dialog/content", "80");
unsortMap.put("./cq:dialog", "75");
unsortMap.put("./cq:dialog/content/items/tabs/items/tab2/items/columns/items", "40");
unsortMap.put("./cq:dialog/content/sling:resourcetype", "granite/ui/components/coral/foundation/container");
I would like to sort it as based on the length of the key, for example if the key has less number of "/" then it will be the on top.
Expected output:
./cq:dialog
./cq:dialog/content/
./cq:dialog/content/sling:resourcetype
./cq:dialog/content/items/tabs/items/tab1/items/columns/items
./cq:dialog/content/items/tabs/items/tab2/items/columns/items
So for this, I write like this:
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
It does not give output as expected because it does not compare based on "/". I have tried custom comparator but could not get the expected result.
答案1
得分: 3
仅比较长度时,我们可以在自定义的比较器中使用 Integer.compare
。<sup>示例</sup>
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted((a, b) -> Integer.compare(a.getKey().length(), b.getKey().length()))
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
当然,你也可以使用这个自定义比较器创建一个 TreeMap
,这样新的键仍然会被正确排序。
final NavigableMap<String, String> sortedMap = new TreeMap<>(
(a, b) -> a.length() != b.length() ? Integer.compare(a.length(), b.length()) : a.compareTo(b));
sortedMap.putAll(unsortMap);
<hr>
为了比较斜杠的数量,我们可以在两个字符串的字符上进行过滤。
final NavigableMap<String, String> sortedMap = new TreeMap<>((a, b) -> {
final long slashes1 = a.chars().filter(c -> c == '/').count();
final long slashes2 = b.chars().filter(c -> c == '/').count();
return slashes1 != slashes2 ? Long.compare(slashes1, slashes2) : a.compareTo(b);
});
sortedMap.putAll(unsortMap);
正如Andreas建议的那样,可以使用.thenComparing
简化比较器:
final NavigableMap<String, String> sortedMap = new TreeMap<>(
Comparator.comparingLong((String s) -> s.chars().filter(c -> c == '/').count())
.thenComparing(Comparator.naturalOrder()));
或者:
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted((a, b) -> Long.compare(a.getKey().chars().filter(c -> c == '/').count(), b.getKey().chars().filter(c -> c == '/').count()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
LinkedHashMap::new));
英文:
To only compare the lengths, we can use Integer.compare
in a custom Comparator. <sup>Demo</sup>
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted((a, b) -> Integer.compare(a.getKey().length(), b.getKey().length()))
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
Of course, you could also create a TreeMap
with this custom Comparator so that new keys will still be ordered correctly.
final NavigableMap<String, String> sortedMap = new TreeMap<>(
(a, b) -> a.length() != b.length() ? Integer.compare(a.length(), b.length()) : a.compareTo(b));
sortedMap.putAll(unsortMap);
<hr>
In order to compare the number of slashes, we can filter over the characters of both Strings.
final NavigableMap<String, String> sortedMap = new TreeMap<>((a, b) -> {
final long slashes1 = a.chars().filter(c -> c == '/').count();
final long slashes2 = b.chars().filter(c -> c == '/').count();
return slashes1 != slashes2 ? Long.compare(slashes1, slashes2) : a.compareTo(b);
});
sortedMap.putAll(unsortMap);
As Andreas suggested, the comparator can be simplified using .thenComparing
:
final NavigableMap<String, String> sortedMap = new TreeMap<>(
Comparator.comparingLong((String s) -> s.chars().filter(c -> c == '/').count())
.thenComparing(Comparator.naturalOrder()));
Alternatively:
Map<String, String> sortedMap = unsortMap.entrySet().stream()
.sorted((a, b) -> Long.compare(a.getKey().chars().filter(c->c=='/').count(), b.getKey().chars().filter(c->c=='/').count()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
LinkedHashMap::new));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论