如何在Java 8中给重复键的Map添加值

7

我想在Java 8中重复键的Map中添加值。

例如:

如果strArr是["B:-1", "A:1", "B:3", "A:5"],那么我的程序应该返回字符串A:6,B:2

我的最终输出字符串应按字母顺序返回键。排除在加总后的值为0的键。

输入:new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"}

输出:B:3,Y:1

输入:new String[] {"Z:0", "A:-1"}

输出:A:-1

尝试的代码:

public static String Output(String[] strArr) {
       //strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
        Map<String, Double> kvs =
                Arrays.asList(strArr)
                    .stream()
                    .map(elem -> elem.split(":"))
                    .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1])));
        
        kvs.entrySet().forEach(entry->{
            System.out.println(entry.getKey() + " " + entry.getValue());  
         });
        
        return strArr[0];
      }

错误:

在主线程中发生异常 java.lang.IllegalStateException: 重复的关键字 -1.0

我该如何解决这个问题?


创建Map时,您添加了相同的键。只需将您的“Map”替换为“List<Pair>”。 - Mister_Jesus
我该如何避免这个问题并解决它? - jaxij
你不能向映射中添加重复的键。只能替换先前的值。 - Mister_Jesus
你能给我建议如何解决这个问题吗? - jaxij
您可以使用 Map::compute 来修改当前值(无论键是否存在)。 - Mister_Jesus
3个回答

7
您应该在第一个流中声明合并策略:
.collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1]), Double::sum));

然后通过零值过滤 Map:

  .filter(s-> s.getValue() != 0)

要按键进行排序,请使用:

   .sorted(Map.Entry.comparingByKey())

结果代码:

   String [] strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
    Map<String, Double> kvs =
            Arrays.asList(strArr)
                    .stream()
                    .map(elem -> elem.split(":"))
                    .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1]), Double::sum));

    kvs.entrySet().stream()
            .filter(s-> s.getValue() != 0)
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry->{
        System.out.println(entry.getKey() + " " + entry.getValue());w
    });

4

对我来说它有效,我使用整数而不是双精度,并使用summaringInt()函数对具有相同键的值进行求和:

        String[] strArr = new String[] { "X:-1", "Y:1", "X:-4", "B:3", "X:5" };

    Map<String, IntSummaryStatistics> collect = Arrays.asList(strArr)
        .stream()
        .map(elem -> elem.split(":"))
        .collect(Collectors.groupingBy(e -> e[0], Collectors.summarizingInt(e -> Integer.parseInt(e[1]))));

    System.out.println("Result:");

    collect.entrySet().stream()
        .filter(e -> e.getValue().getSum() != 0)
        .sorted(Map.Entry.comparingByKey())
        .forEach(e -> System.out.println("Key : " + e.getKey() + ", Value : " + e.getValue().getSum()));

Collectors.summingInt 也可以。 - Nowhere Man

4

也可以使用 Collectors.groupingBy + Collectors.summingDouble,通过收集到 TreeMap 中来构建一个已排序的 kvs 映射:

String [] strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
Map<String, Double> kvs = Arrays.stream(strArr)
        .map(elem -> elem.split(":"))
        .collect(Collectors.groupingBy(
            e -> e[0], 
            TreeMap::new, // sort by key
            Collectors.summingDouble(e -> Double.parseDouble(e[1]))
        ));
System.out.println(kvs);  // entries with 0 value yet to be removed
// output
// {B=3.0, X=0.0, Y=1.0}

如果只需要按照所述格式打印地图(不包含0值),可以按如下方式进行:
System.out.println(
    kvs.entrySet().stream()
        .filter(e -> e.getValue() != 0)
        .map(e -> new StringBuilder(e.getKey()).append(':').append(e.getValue().intValue()) )
        .collect(Collectors.joining(","))
);
// output
// B:3,Y:1

如果需要从 kvs 中删除0值,可以对其条目集应用 removeIf
kvs.entrySet().removeIf(e -> e.getValue() == 0);
System.out.println(kvs);
// output
// {B=3.0, Y=1.0}

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