Search code examples
jsonspring-bootjava-streamconcatenationdto

How to Extract list within a list?


I have two JSON responses that I have to combine to one response.

First JSON Response: (DTO2)

  "data1": [{
      "id": "ABC",
      "variables": [{
        "id": "XYZ",
        "name":"name",
        "description":"description"}]
    }]

  class A{
List <Data1> data1; 

class Data1 data1 {
....
List<Variables> variables;
}}

Second JSON response: (DTO1)

  "data2": [{
      "id": "XYZ",
      "parameters": [{
       "timeStamp":"12345678",
        "value": "value",
        "category":"category" }]
    }]

  Class B{
List <Data2> data2;

public Data2 data2 {
.....
List<Parameters> parameters;
}
}

Final Response should be like this:

[{
  "id":"XYZ",
   "name":"name",
   "description":"description",
   "parameter":{
    "value": "value",
    "category":"category",
    "timeStamp":"timeStamp" 
    }

}]

I created DTO for each response. I have to check for the id and combine the response for the final one.

I have used nested for each and combined it.

 // received response is mapped to classA

classAResponse.getData1.forEach{ a ->

a.getVariables.forEach{ v ->

classBResponse.getData2.forEach { b ->

b.getParameters.forEach{ p ->

if(a.getId.equals(b.getId)) then
 new Response(....)

});
});.....

Is there any better way?


Solution

  • Assuming that:

    1. Both dtos examples represents arrays with more than one object.
    2. You have to extract a list of Responses only from Parameters and Variables that appears in both arrays, and exclude them otherwise.

    Then I think I would use a HashMap due to his operations with O(1) complexity which means that the time needed to get and put values doesn't depend on the size of the collection, it's delay can be estimated as a constant value (please take a look at the concept of hashing and how it's used in this implementation of Map).

    So I think that a better solution would be something like these:

    Set<Response> responses = new HashSet<>(); //Or whatever collection you want.
    HashMap<String, Variables> mapWithAValues = new HashMap<>(); //Key of type string, Value of type Variables.
    
    // Put in the map every nested variable in the list of Data1
    classAResponse.getData1()
    .stream()
    .flatMap(d -> d.getVariables().stream())
    .forEach(v -> mapWithAValues.put(v.getId(), v));
    
    classBResponse.getData2()
    .stream()
    .forEach(data2 -> {
      String id = data2.getId();
      // Search for a variable corresponding to this parameter.
      Variables aValue = mapWithAValues.get(id);
      if(aValue != null) {
        List<Parameter> parameters = data2.getParameters();
        // Merge data in a Response
        Response newResponse = new Response(...);
        ...
        //Add response to the list of responses.
        responses.add(newResponse);
      }
    });
    return responses;
    

    This solution will have a complexity of O(N), where N is the sum of the numbers of variables and the number of parameters available. In your example, I think the complexity would be O(d2^V) because you need to iterate V (number of variables available) times the list of d2 (number of data 2 values available) items.

    Hope this helps :)