Skip to content

Java code refactor with stream Collectors.groupingby()

I try to get a Map with Collectors.groupingBy() but I have no idea how to create…

I have a List from jpa jquerydsl

List<Tuple> list = mydata

the data is like

[memberId=1, departmentId=1]
[memberId=1, departmentId=2]
[memberId=2, departmentId=3]
[memberId=3, departmentId=4]

this is my Member class

public class Member {
    private Long id;
    private List<Long> departmentIds;
}

I want to parse tuple list to member Map By member id

data is like

Map<Long, Member>
{
1=Member(id=1, departmentIds=[1,2]), 
2=Member(id=2, departmentIds=[3]),
3=Member(id=3, departmentIds=[4])
}

this is my code without Collectors.groupingBy()

Map<Long, Member> map = new HashMap<>();
for (Tuple tuple : tupleList) {
    Long id = tuple.get(member.id); // this is jpa querydsl type
    Long departmentId = tuple.get(department.id); // this is jpa querydsl type
    if (map.containsKey(id)) {
        Member member = map.get(id);
        List<Long> departmentIds = member.getDepartmentIds();
        departmentIds.add(departmentId);
        member.setDepartmentIds(departmentIds);
        map.put(id, member);
    } else {
        Member member = new Member();
        member.setId(id);
        List<Long> departmentIds = new ArrayList<>();
        departmentIds.add(departmentId);
        Member.setDepartmentIds(departmentIds);
        map.put(id, member);
    }
}

I want to refactor my code with Collectors.groupingBy()

tupleList.stream.collect(groupingBy(... mapping()))  .....

But I have no idea

How to create ? thanks…!

Answer

Maybe this code answers your question

import org.apache.commons.lang3.tuple.Pair;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Scratch {
    public static void main(String[] args) {
        List<Pair<Long, Long>> myData = List.of(
                Pair.<Long, Long>of(1L, 1L),
                Pair.<Long, Long>of(1L, 2L),
                Pair.<Long, Long>of(1L, 4L),
                Pair.<Long, Long>of(2L, 3L),
                Pair.<Long, Long>of(3L, 4L)
        );

        final Map<Long, Member> memberMap = myData.stream()
                .collect(Collectors.toMap(Pair::getKey,
                        pair -> new Member(pair.getKey(), pair.getValue()),
                        (member1, member2) -> member1.addAllDepartmentId(member2.departmentIds)
                ));

        System.out.println(memberMap);
    }

    public static class Member {
        private Long id;
        private List<Long> departmentIds;

        public Member(Long id, Long departmentId) {
            this.id = id;
            this.departmentIds = new ArrayList<>();
            this.departmentIds.add(departmentId);
        }

        public Member addAllDepartmentId(List<Long> departmentId) {
            this.departmentIds.addAll(departmentId);
            return this;
        }

        @Override
        public String toString() {
            return "Member{" +
                    "id=" + id +
                    ", departmentIds=" + departmentIds +
                    '}';
        }
    }

}

The code prints

{1=Member{id=1, departmentIds=[1, 2, 4]}, 2=Member{id=2, departmentIds=[3]}, 3=Member{id=3, departmentIds=[4]}}

Which I think is what you want. I used org.apache.commons.lang3.tuple.Pair where you have another tuple class. A added some helper methods to the Member class to make the code a bit cleaner. The trick is using toMap and supplying a merge function here (member1, member2) -> member1.addAllDepartmentId(member2.departmentIds) to combine the department IDs.