如何根据键的长度对映射进行排序

huangapple go评论159阅读模式
英文:

how to sort map based on key length

问题

  1. 我有这个地图
  2. Map<String, String> unsortMap = new HashMap<String, String>();
  3. unsortMap.put("./cq:dialog/content/items/tabs/items/tab1/items/columns/items", "40");
  4. unsortMap.put("./cq:dialog/content", "80");
  5. unsortMap.put("./cq:dialog", "75");
  6. unsortMap.put("./cq:dialog/content/items/tabs/items/tab2/items/columns/items", "40");
  7. unsortMap.put("./cq:dialog/content/sling:resourcetype", "granite/ui/components/coral/foundation/container");
  8. 我想根据键的长度对其进行排序例如如果键的/数量较少则它将位于顶部
  9. 期望的输出
  10. ./cq:dialog
  11. ./cq:dialog/content/
  12. ./cq:dialog/content/sling:resourcetype
  13. ./cq:dialog/content/items/tabs/items/tab1/items/columns/items
  14. ./cq:dialog/content/items/tabs/items/tab2/items/columns/items
  15. 为此我写了以下代码
  16. Map<String, String> sortedMap = unsortMap.entrySet().stream()
  17. .sorted((entry1, entry2) -> {
  18. int slashes1 = entry1.getKey().length() - entry1.getKey().replace("/", "").length();
  19. int slashes2 = entry2.getKey().length() - entry2.getKey().replace("/", "").length();
  20. return Integer.compare(slashes1, slashes2);
  21. })
  22. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
  23. (oldValue, newValue) -> oldValue, LinkedHashMap::new));
  24. 这样做是因为它会基于/的数量进行比较我尝试了自定义比较器但没有获得预期的结果
英文:

I have this map:

  1. Map &lt; String, String &gt; unsortMap = new HashMap &lt; String, String &gt; ();
  2. unsortMap.put(&quot;./cq:dialog/content/items/tabs/items/tab1/items/columns/items&quot;, &quot;40&quot;);
  3. unsortMap.put(&quot;./cq:dialog/content&quot;, &quot;80&quot;);
  4. unsortMap.put(&quot;./cq:dialog&quot;, &quot;75&quot;);
  5. unsortMap.put(&quot;./cq:dialog/content/items/tabs/items/tab2/items/columns/items&quot;, &quot;40&quot;);
  6. unsortMap.put(&quot;./cq:dialog/content/sling:resourcetype&quot;, &quot;granite/ui/components/coral/foundation/container&quot;);

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:

  1. ./cq:dialog
  2. ./cq:dialog/content/
  3. ./cq:dialog/content/sling:resourcetype
  4. ./cq:dialog/content/items/tabs/items/tab1/items/columns/items
  5. ./cq:dialog/content/items/tabs/items/tab2/items/columns/items

So for this, I write like this:

  1. Map&lt;String, String&gt; sortedMap = unsortMap.entrySet().stream()
  2. .sorted(Map.Entry.comparingByKey())
  3. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
  4. (oldValue, newValue) -&gt; 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>

  1. Map<String, String> sortedMap = unsortMap.entrySet().stream()
  2. .sorted((a, b) -> Integer.compare(a.getKey().length(), b.getKey().length()))
  3. .collect(Collectors.toMap(Map.Entry::getKey,
  4. Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));

当然,你也可以使用这个自定义比较器创建一个 TreeMap,这样新的键仍然会被正确排序。

  1. final NavigableMap<String, String> sortedMap = new TreeMap<>(
  2. (a, b) -> a.length() != b.length() ? Integer.compare(a.length(), b.length()) : a.compareTo(b));
  3. sortedMap.putAll(unsortMap);

<hr>

为了比较斜杠的数量,我们可以在两个字符串的字符上进行过滤。

  1. final NavigableMap<String, String> sortedMap = new TreeMap<>((a, b) -> {
  2. final long slashes1 = a.chars().filter(c -> c == '/').count();
  3. final long slashes2 = b.chars().filter(c -> c == '/').count();
  4. return slashes1 != slashes2 ? Long.compare(slashes1, slashes2) : a.compareTo(b);
  5. });
  6. sortedMap.putAll(unsortMap);

正如Andreas建议的那样,可以使用.thenComparing简化比较器:

  1. final NavigableMap<String, String> sortedMap = new TreeMap<>(
  2. Comparator.comparingLong((String s) -> s.chars().filter(c -> c == '/').count())
  3. .thenComparing(Comparator.naturalOrder()));

或者:

  1. Map<String, String> sortedMap = unsortMap.entrySet().stream()
  2. .sorted((a, b) -> Long.compare(a.getKey().chars().filter(c -> c == '/').count(), b.getKey().chars().filter(c -> c == '/').count()))
  3. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
  4. LinkedHashMap::new));
英文:

To only compare the lengths, we can use Integer.compare in a custom Comparator. <sup>Demo</sup>

  1. Map&lt;String, String&gt; sortedMap = unsortMap.entrySet().stream()
  2. .sorted((a, b) -&gt; Integer.compare(a.getKey().length(), b.getKey().length()))
  3. .collect(Collectors.toMap(Map.Entry::getKey,
  4. Map.Entry::getValue, (oldValue, newValue) -&gt; oldValue, LinkedHashMap::new));

Of course, you could also create a TreeMap with this custom Comparator so that new keys will still be ordered correctly.

  1. final NavigableMap&lt;String, String&gt; sortedMap = new TreeMap&lt;&gt;(
  2. (a, b) -&gt; a.length() != b.length() ? Integer.compare(a.length(), b.length()) : a.compareTo(b));
  3. sortedMap.putAll(unsortMap);

<hr>

In order to compare the number of slashes, we can filter over the characters of both Strings.

  1. final NavigableMap&lt;String, String&gt; sortedMap = new TreeMap&lt;&gt;((a, b) -&gt; {
  2. final long slashes1 = a.chars().filter(c -&gt; c == &#39;/&#39;).count();
  3. final long slashes2 = b.chars().filter(c -&gt; c == &#39;/&#39;).count();
  4. return slashes1 != slashes2 ? Long.compare(slashes1, slashes2) : a.compareTo(b);
  5. });
  6. sortedMap.putAll(unsortMap);

As Andreas suggested, the comparator can be simplified using .thenComparing:

  1. final NavigableMap&lt;String, String&gt; sortedMap = new TreeMap&lt;&gt;(
  2. Comparator.comparingLong((String s) -&gt; s.chars().filter(c -&gt; c == &#39;/&#39;).count())
  3. .thenComparing(Comparator.naturalOrder()));

Alternatively:

  1. Map&lt;String, String&gt; sortedMap = unsortMap.entrySet().stream()
  2. .sorted((a, b) -&gt; Long.compare(a.getKey().chars().filter(c-&gt;c==&#39;/&#39;).count(), b.getKey().chars().filter(c-&gt;c==&#39;/&#39;).count()))
  3. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -&gt; oldValue,
  4. LinkedHashMap::new));

huangapple
  • 本文由 发表于 2020年7月26日 23:22:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63102080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定