2

I have Stream<Map<String, String>> where each map is like a separate record and contains two entries:

  1. Car Id ("ID", "1003")
  2. Kilometers ("KMI", "500")

This list might contain maps which are duplicate in a way that 2 or more maps could have the same value of car id entry. Basically this: entry1.get("ID") == entry2.get("ID"). what i want to do is to remove maps with duplicate ids but then also to merge KMI values together. this:

{"ID":"1003","KMI":"500"}, {"ID":"1003","KMI":"400"}, {"ID":"1004","KMI":"200"}

should become this:

{"ID":"1003","KMI":"900"}, {"ID":"1004","KMI":"200"}

I have tried doing it with streams API alone, but I can't wrap my head around this. I tried modifying a similar example which was having List of objects here is what I got so far:

List<Map<String, String>> result = new ArrayList<>(
    queryKmAll.collect(
        Collectors.toMap(a1 -> a1.get("ID")), Function.identity(), (Map<String, String> m2, Map<String, String> m1) -> {
            m1.put("KMI", String.valueOf(Double.parseDouble(m1.get("KMI")) + Double.parseDouble(m2.get("KMI"))));

            return m1;
        })
    )
);
1
  • 2
    So, what is the problem with that code? (Side note: why don't you define a class, with two properties, having the appropriate type, and methods allowing to do what you want?) Commented Apr 26, 2019 at 6:37

2 Answers 2

2

I have picked up from where OP left. I have modified your logic a bit to return what you wanted. Have a look at it. Hope it helps

Collectors.toMap will return a map which will have ID as key and sum of KMI for Function.identity() cases. So the return would be Map<Object,Map<String,String>>. Because expected output is Stream<Map<String,String> , I added .values().stream().

Stream<Map<String, String>> result = queryKmAll.collect(Collectors.toMap(a1 -> a1.get("ID"),
            Function.identity(), (Map<String, String> m2, Map<String, String> m1) -> {
                m1.put("KMI",
                        String.valueOf(Double.parseDouble(m1.get("KMI")) + Double.parseDouble(m2.get("KMI"))));

                return m1;
            })).values().stream();

result.forEach(System.out::println);
Sign up to request clarification or add additional context in comments.

1 Comment

Although all solutions where useful and working for my case im accepting this one because its pretty simple and it works without doing any modifications even when adding more rows elements into the map. I will use this, at least for now. I will consider to moving from map to a class as @Sindbad90 have suggested.
1

What you're looking for is Collectors.groupingBy:

    Map<String, Long> summary = Stream
        .of(
            new HashMap<String, String>() {{
              put("ID", "1003");
              put("KMI", "500");
            }},
            new HashMap<String, String>() {{
              put("ID", "1003");
              put("KMI", "400");
            }},
            new HashMap<String, String>() {{
              put("ID", "1004");
              put("KMI", "200");
            }}
        )
        .collect(Collectors.groupingBy(
            m -> m.get("ID"),
            Collectors.summingLong(m -> Long.valueOf(m.get("KMI")))
        ));

    System.out.println(summary);

Also, you could replace the map with an class, say Summary:

  public class Summary {

    public Summary(String id, Long kmi) {
      this.id = id;
      this.kmi = kmi;
    }

    private String id;
    private Long kmi;

    public String getId() {
      return id;
    }

    public Long getKmi() {
      return kmi;
    }
  }

And then use:

    Map<String, Long> summary = Stream
        .of(
            new Summary("1003", 500L),
            new Summary("1003", 400L),
            new Summary("1004", 200L)
        )
        .collect(Collectors.groupingBy(
            s -> s.getId(),
            Collectors.summingLong(s -> s.getKmi())
        ));

    System.out.println(summary);

Prints: {1004=200, 1003=900}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.