Optimum way to merge elements in an ArrayList in java

Viewed 69

I have a List<QueryResult> in which the QueryResult is structured like this -

class QueryResult{
    int projectId;
    int taskId;
    String projectName;
    String projectManager;
}
    

Now the results that i am getting for QueryResult is something like this :

queryResult1 -> {projectId:1, taskId:**21**, projectName="xyz" projectManager="abc"}
queryResult1 -> {projectId:1, taskId:**22**, projectName="xyz" projectManager="abc"}
queryResult1 -> {projectId:1, taskId:**23**, projectName="xyz" projectManager="abc"}
queryResult1 -> {projectId:2, taskId:31, projectName="prj2" projectManager="dc"}
queryResult1 -> {projectId:2, taskId:41, projectName="prj2" projectManager="dc"}

Now the output that i want is something like :

DesiredOutput -> 
  {projectId:1,taskIds:{21,22,23}, projectName="xyz" projectManager="abc"}
  {projectId:2,taskIds:{31,41}, projectName="prj2" projectManager="dc"}

So I want to convert multiple rows into one for one projectId and merging different taskIds together. Rest other details apart from taskId remains the same for a particular project ID.

I am new to java 8, wanted to do this in a functional style. My solution is to stream all the queryResults object and then create a Map<ProjectID, List<TaskIds>>, but not sure how to get it in a functional style and also will have to merge my results to form the resultant output. I am looking for the most optimum approach for this little problem.

2 Answers
class QueryResultTransformed{
    int projectId;
    List<Integer> taskId;
    String projectName;
    String projectManager;
    }
List<QueryResultTransformed> result = queryResults.stream()
                                    .collect(groupingBy(QueryResult::getProjectId))
                                    .entrySet()
                                    .stream()
                                    .map(e->{
                                    QueryResultTransformed obj = new QueryResultTransformed();
                                    List<QueryResult> list= e.getValue()
                                    List<Integer> taskIds = list.stream().map(QueryResult::getTaskId).collect(Collectors.toList());
                                    obj.setProjectId(e.getKey());
                                    obj.setProjectName(list.get(0).getProjectName());
                                    obj.setProjectManager(list.get(0).getProjectManager());
                                    obj.setTaskIds(taskIds);
                                    return obj;
                                  }).collect(Collectors.toList());

                

A sample code to demonstrate that would include, creating a new container class for the final expected result, I have used record for avoiding the boiler plate for this particular case.

record QueryResultTasks(int projectId, String projectName,
                        String projectManager, List<Integer> taskIds) {
}

then you can iterate the query results and create an intermediate map for projected to taskId grouping

Map<Integer, List<Integer>> taskGrouping = queryResults.stream()
        .collect(Collectors.groupingBy(QueryResult::getProjectId,
                Collectors.mapping(QueryResult::getTaskId, Collectors.toList())));

further, the initial list and the intermediate map can be used to obtain the desired result using the map operation

List<QueryResultTasks> resultTasks = queryResults.stream()
        .map(qr -> new QueryResultTasks(qr.getProjectId(), qr.getProjectName(),
                qr.getProjectManager(), taskGrouping.get(qr.getProjectId())))
        .collect(Collectors.toList());
Related