jaxij
jaxij

Reputation: 151

How to add values in duplicated key Map in Java 8

I want to add values in duplicated key Map in Java 8.

As an example:

For example: if strArr is ["B:-1", "A:1", "B:3", "A:5"] then my program should return the string A:6,B:2.

My final output string should return the keys in alphabetical order. Exclude keys that have a value of 0 after being summed up.

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

Output: B:3,Y:1

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

Output: A:-1

Tried code:

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

Error:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key -1.0

How can I fix this?

Upvotes: 7

Views: 423

Answers (3)

Nowhere Man
Nowhere Man

Reputation: 19575

It is also possible to use Collectors.groupingBy + Collectors.summingDouble to build a sorted kvs map by collecting to TreeMap:

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}

If it is required just to print the map in the mentioned format without 0 values, it may be done like this:

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

If 0 values need to be removed from kvs, a removeIf may be applied to its entry set:

kvs.entrySet().removeIf(e -> e.getValue() == 0);
System.out.println(kvs);
// output
// {B=3.0, Y=1.0}

Upvotes: 4

tomeszmh
tomeszmh

Reputation: 238

It's working for me , I used Integer instead of double and summaringInt() function for sum values with same key:

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

Upvotes: 4

Dmitrii B
Dmitrii B

Reputation: 2860

You should declare a merging strategy in the first stream:

.collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1]), Double::sum));

and then filtered Map by zero value:

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

for sorting by key use:

   .sorted(Map.Entry.comparingByKey())

result code:

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

Upvotes: 7

Related Questions