Search code examples
javajava-stream

How to convert list to map with multiple keys and value as list using java stream


I have list of Users(id,ssn,name) and need to convert as Map of list of ssns and list of ids. Could you help with this?

List.of(new User(1, "ssn1", "user1"), new User(2, "ssn2", "user2"), new User(3, "ssn3", "user3"))

Map with 2 keys("SSNs","IDs") and list as value
"SSNs" -  List("ssn1","ssn2","ssn3")
"IDs" -  List(1,2,3)

Code

public class Test {

    public static void main(String[] args) {

        List<User> users = List.of(new User(1, "ssn1", "user1"), new User(2, "ssn2", "user2"),
                new User(3, "ssn3", "user3"));

        Map<String, List<Object>> userMap = users.stream().collect(Collectors.groupingBy(User::getSsn));
    
    }

}

class User {
    public int getId() {
        return id;
    }

    public String getSsn() {
        return ssn;
    }

    public String getName() {
        return name;
    }

    int id;
    String ssn;
    String name;

    public User(int id, String ssn, String name) {
        this.id = id;
        this.ssn = ssn;
        this.name = name;
    }
}

Update: Updated List<User> to List<Object>.


Solution

  • It’s not necessarily an improvement over a loop solution but you can solve the task using the Stream API like this:

    Map<String, List<Object>> result = users.stream()
        .collect(Collectors.teeing(
            Collectors.mapping(User::getId, Collectors.toList()),
            Collectors.mapping(User::getSsn, Collectors.toList()),
            (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));
    

    Above example works with Eclipse. It seems, javac has problems with the type inference. The following works on both:

    Map<String, List<Object>> result = users.stream()
        .collect(Collectors.teeing(
            Collectors.mapping(User::getId, Collectors.<Object>toList()),
            Collectors.mapping(User::getSsn, Collectors.<Object>toList()),
            (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));
    

    Alternatively

    Map<String, List<?>> result = users.stream()
        .collect(Collectors.teeing(
            Collectors.mapping(User::getId, Collectors.toList()),
            Collectors.mapping(User::getSsn, Collectors.toList()),
            (id, ssn) -> Map.of("IDs", id, "SSNs", ssn)));