【问题标题】:Using streams to collect to Map使用流收集到 Map
【发布时间】:2018-05-30 06:57:30
【问题描述】:

我有以下TreeMap

TreeMap<Long,String> gasType = new TreeMap<>(); // Long, "Integer-Double"
gasType.put(1L, "7-1.50");
gasType.put(2L, "7-1.50");
gasType.put(3L, "7-3.00");
gasType.put(4L, "8-5.00");
gasType.put(5L, "8-7.00");
Map<Integer,TreeSet<Long>> capacities = new TreeMap<>);

键的形式为1LLong),值的形式为"7-1.50"String 的连接,intdouble- 分隔) .

我需要创建一个新的TreeMap,其中的键是通过获取原始Map 的值的int 部分获得的(例如,对于值"7-1.50",新键将为@ 987654334@)。新的Map 的值将是一个TreeSet,其中包含与新键匹配的原始Map 的所有键。

因此,对于上面的输入,7 键的值将是 Set {1L,2L,3L}。

没有Streams 我也可以做到这一点,但我想用Streams 做到这一点。任何帮助表示赞赏。谢谢。

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    这是一种方法:

    Map<Integer,TreeSet<Long>> capacities = 
      gasType.entrySet()
             .stream ()
             .collect(Collectors.groupingBy (e -> Integer.parseInt(e.getValue().substring(0,e.getValue ().indexOf("-"))),
                                             TreeMap::new,
                                             Collectors.mapping (Map.Entry::getKey,
                                                                 Collectors.toCollection(TreeSet::new))));
    

    我修改了原始代码以支持多位整数,因为您似乎想要这样。

    这会产生Map

    {7=[1, 2, 3], 8=[4, 5]}
    

    如果您不关心生成的 MapSets 的顺序,您可以让 JDK 决定实现,这会在一定程度上简化代码:

    Map<Integer,Set<Long>> capacities = 
      gasType.entrySet()
             .stream ()
             .collect(Collectors.groupingBy (e -> Integer.parseInt(e.getValue().substring(0,e.getValue ().indexOf("-"))),
                                             Collectors.mapping (Map.Entry::getKey,
                                                                 Collectors.toSet())));
    

    【讨论】:

    • @Aominè 看到结尾附近的评论消除了这种假设。
    • 是的,刚刚开始了 :)
    • 是的,整数并不总是个位数,您提供了两种可能性。这是一个优雅的解决方案!衷心感谢您!谢谢。
    【解决方案2】:

    你可以试试这个,

    final Map<Integer, Set<Long>> map = gasType.entrySet().stream()
            .collect(Collectors.groupingBy(entry -> Integer.parseInt(entry.getValue().substring(0, 1)),
                    Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
    

    更新

    如果您想根据“-”拆分值,因为可能不止一位,您可以这样更改:

    final Map<Integer, Set<Long>> map = gasType.entrySet().stream()
            .collect(Collectors.groupingBy(entry -> Integer.parseInt(entry.getValue().split("-")[0]),
                    Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
    

    【讨论】:

    • 有没有什么办法可以根据“-”分割数值,这样除了个位数之外也可以使用?
    • 我已根据您的新要求更改了答案。
    • 谢谢@Ravindra 先生。
    【解决方案3】:

    其他解决方案是这样的

    list = gasType.entrySet()
                .stream()
                .map(m -> new AbstractMap.SimpleImmutableEntry<Integer, Long>(Integer.valueOf(m.getValue().split("-")[0]), m.getKey()))
                 .collect(Collectors.toList());
    

    第二步:

    list.stream()
        .collect(Collectors.groupingBy(Map.Entry::getKey,
        Collectors.mapping(Map.Entry::getValue,Collectors.toCollection(TreeSet::new))));
    

    或一步到位:

    gasType.entrySet()
                .stream()
                .map(m -> new AbstractMap.SimpleImmutableEntry<>(Integer.valueOf(m.getValue().split("-")[0]), m.getKey()))
                .collect(Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue, Collectors.toCollection(TreeSet::new))))
    

    【讨论】:

    • 我也试试这个,谢谢!非常感谢先生。
    • 为什么需要映射到 SimpleEntry?这只会增加可以避免的额外开销,并且收集到列表只是为了在流管道的中间从它创建一个流是次优的。我会在 groupingBy 中完成所有键提取和值提取。
    • 你是对的,但我认为它不应该与其他答案相同。gasType.entrySet() .stream() .collect(Collectors.groupingBy(m-&gt;Integer.valueOf(m.getValue().split("-")[0]), Collectors.mapping(Map.Entry::getKey,Collectors.toCollection(TreeSet::new))));
    猜你喜欢
    • 1970-01-01
    • 2018-02-02
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多