按嵌套映射的值对外部映射进行排序

时间:2018-06-08 04:11:03

标签: java sorting java-stream comparator

嵌套地图中的列表大小外部地图Map<String, Map<String, List<Integer>>>进行排序,保留外键和内键,如前所述。

1 个答案:

答案 0 :(得分:2)

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

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代表其大小,并按降序排序,并使用替换操作作为外部地图的替换函数:< / p>

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(),并使用列表的大小提供比较器。外部地图的比较器仍然可以使用内部地图此时已经排序的事实,但也必须提取列表的size()以进行比较。