根据嵌套地图的值对外部地图进行排序

Sort the outer map by the value of the nested map

嵌套中的列表大小外部映射Map<String, Map<String, List<Integer>>>进行排序] 像以前一样保留外键和内键的地图。

您可以通过概括该过程来解决此问题:

private static <K,V,R> Map<K,R>
                       replaceAndSortValues(Map<K,V> m, Function<V,R> f, Comparator<R> c) {
    return m.entrySet().stream()
        .map(e -> Map.entry(e.getKey(), f.apply(e.getValue())))
        .sorted(Map.Entry.comparingByValue(c.reversed()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                  (a,b) -> { throw new AssertionError(); },
                                  LinkedHashMap::new));
}

此方法使用与指定键相同的键创建一个新映射,使用指定函数替换所有值并根据指定比较器的反转对条目进行排序。它使用 Java 9 的 Map.entry(…, …) 工厂。如果您必须支持 Java 8 或 null 个键或值,您可以改用 new AbstractMap.SimpleImmutableEntry<>(…, …)

此方法现在可用于将内部地图的 List 替换为代表其大小的 Integer 并按降序排列,并将替换操作用作外部地图的替换功能:

public static Map<String, Map<String, Integer>>
              getCallWithStateSizeGroup(ThreadDumpDo threadDumpDo) {
    return replaceAndSortValues(getCallStackWithStateGroup(threadDumpDo),
        m -> replaceAndSortValues(m, List::size, Comparator.<Integer>naturalOrder()),
        Comparator.comparing(m -> m.values().iterator().next()));
}

这与您发布的解决方案基本相同。外层映射的比较器利用了新的内层映射已经排序的事实,所以它们的第一个值是最大值。但是一定不能有空的内图。

这很容易适应以保留 List<ThreadDo> 并按大小对它们进行排序:

public static Map<String, Map<String, List<ThreadDo>>>
              getCallWithStateSizeGroup(ThreadDumpDo threadDumpDo) {
    return replaceAndSortValues(getCallStackWithStateGroup(threadDumpDo),
        m -> replaceAndSortValues(m, Function.identity(),
                                  Comparator.comparingInt(List::size)),
        Comparator.comparingInt(m -> m.values().iterator().next().size()));
}

我们只需要将内部映射的替换函数更改为 Function.identity() 并提供一个使用列表大小的比较器。 outer map 的比较器此时仍然可以利用 inner maps 已经排序的事实,但也必须提取列表的 size() 进行比较。