Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Collections Merging List

I am trying to merge the collections using employee name.

I have a MainDTO which has List<Employee(name, List<Address(String)>)>

Employee has String name and List Address Address is a String.

MainDTO -> List<Employee> empList;
Employee-> String name, List<String>

I have input data:

( ("emp1",[("KY"),"("NY")]),
  ("em2",[("KY"),"("NY")]),
  ("emp1",[("MN"),"("FL")]),
  ("emp1",[("TN"),"("AZ")])
)

output will be:

( ("emp1",[("KY"),"("NY"),("MN"),"("FL"),("TN"),"("AZ")]),
  ("em2",[("KY"),"("NY")])
)

Any best way to sort this data using java 8 or java 7.

like image 551
Kumar Avatar asked Mar 03 '26 17:03

Kumar


2 Answers

If Java 9 was an option, you could use flatMapping:

Map<String, List<String>> addressesByEmployeeName = empList
        .stream()
        .collect(groupingBy(
                Employee::getName, flatMapping(
                        e -> e.getAddresses().stream(),
                        toList())));

But I have this weird feeling Java 9 is not an option.

like image 94
shmosel Avatar answered Mar 06 '26 06:03

shmosel


shmosel's answer is nice in that it makes good use of the new JDK 9 flatMapping collector. If JDK 9 isn't an option, it's possible to do something similar in JDK 8, although it's a bit more involved. It performs the flat-mapping operation within the stream, resulting in a stream of pairs of employee name and address. Instead of creating a special pair class I'll use AbstractMap.SimpleEntry.

The basic idea is to stream the list of employees and flat-map them into a stream of pairs of (name, address). Once this is done, collect them into a map, grouping by the name, and collecting the addresses into a list for each group. Here's the code to do that:

import static java.util.AbstractMap.SimpleEntry;
import static java.util.Map.Entry;
import static java.util.stream.Collectors.*;

Map<String, List<String>> mergedMap =
    empList.stream()
           .flatMap(emp -> emp.getAddresses().stream().map(
                        addr -> new SimpleEntry<>(emp.getName(), addr)))
           .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())));

This gives a Map as a result. If you want to create Employee objects from these, you can stream over the entries to create them:

List<Employee> mergedEmps =
    mergedMap.entrySet().stream()
             .map(entry -> new Employee(entry.getKey(), entry.getValue()))
             .collect(toList());

Creation of map entry objects and extracting data from them is somewhat cumbersome, but not terrible. If you want, some of the idioms here can be extracted into utility methods to make things a bit cleaner.

like image 36
Stuart Marks Avatar answered Mar 06 '26 06:03

Stuart Marks



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!