使用流(Stream)收集到Map中

4

我有以下的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<>);

关键字的格式为1L(一个Long),值的格式为"7-1.50"(由intdouble连接而成,用-分隔)。
我需要创建一个新的TreeMap,其中关键字是通过获取原始Map的值的int部分获得的(例如,对于值"7-1.50",新关键字将为7)。新Map的值将是包含所有匹配新关键字的原始Map的关键字的TreeSet
因此,对于上述输入,7键的值将为Set{1L、2L、3L}。
我可以不使用Stream来完成这个操作,但我想使用Stream来实现。非常感谢您的帮助。谢谢。
3个回答

5

以下是一种实现方法:

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]}

如果您不关心结果MapSet的排序,您可以让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è,请看最后附近的评论,它消除了那个假设。 - Eran
好的,我差不多要完成它了 :) - Ousmane D.
是的,整数并不总是单个数字,而您已经提供了两种可能性。这是一个优雅的解决方案!非常感谢您!谢谢。 - Nizamuddin Shaikh

4

你可以尝试这个方法,

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

有没有办法根据“-”拆分值,以便除了单个数字之外还可以利用其他数字? - Nizamuddin Shaikh
2
我已根据您的新要求更改了答案。 - Ravindra Ranwala
感谢Ravindra先生。 - Nizamuddin Shaikh

2
其他解决方案可能是这样的。
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))))

我也会尝试,谢谢!非常感谢您。 - Nizamuddin Shaikh
1
为什么需要映射到SimpleEntry?这只会增加进一步的开销,可以避免,并且仅收集到列表中,以便在流管道的中间创建一个流是次优的。我会在groupingBy中执行所有键提取和值提取。 - Ousmane D.
你说得没错,但我认为它不应该与其他答案相同。gasType.entrySet() .stream() .collect(Collectors.groupingBy(m->Integer.valueOf(m.getValue().split("-")[0]), Collectors.mapping(Map.Entry::getKey,Collectors.toCollection(TreeSet::new)))); - Hadi J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接