代码之家  ›  专栏  ›  技术社区  ›  Hearen

根据嵌套映射的值对外部映射排序

  •  -2
  • Hearen  · 技术社区  · 6 年前

    排序 外面的 地图 Map<String, Map<String, List<Integer>>> 列表大小 嵌套的 地图保持内外键不变。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Holger    6 年前

    你可以通过概括过程来解决这个问题:

    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));
    }
    

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

    现在可以使用此方法替换内部映射 List 带着 Integer s表示其大小并按降序排序,并将替换操作用作外部映射的替换函数:

    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() 以供比较。