Search code examples
javajava-8java-streamflattenflatmap

How can I flatten the below nested object to array of strings?


I am trying to convert below object to array of string

JSON Object

Input :

  [
    {
        "name": "Pantry",
        "childrenItems": [
          {
            "name": "Butter",
            "childrenItems": [
              {
                "name": "Cream",
                "childrenItems": []
              }
            ]
          },
          {
            "name": "Snack",
            "childrenItems": []
          }
        ]
      },
    
     {
        "name": "Medicine",
        "childrenItems": []
      }
    ]

Required Output:

[ "Pantry->Butter->Cream", "Pantry->Snack", "Medicine" ]

My POJO looks like this

@Data
public class CategoryTreeDto {
    private String name;
    private List<CategoryTreeDto> childrenItems;
}

How can I flatten the JSON object of Nested categories using java 8 stream API.

I tried using the recursion and java 8 flatMap function to flatten and concatenate the strings but not getting output as expected.

It is based on parent child relationship, as pantry is a parent and its child is butter and again butter's child is cream and also pantry has another child which is snack.


Solution

  • I think recursion is much simpler than java stream for this particular task.

    public class Test {
    
      public static void main(String[] args) throws IOException {
        List<CategoryTreeDto> list = //get data
        List<String> result = new ArrayList<>();
        for (CategoryTreeDto dto : list) {
          traverse(dto, dto.getName(), result);
        }
        System.out.println(result);
      }
    
      private static void traverse(CategoryTreeDto dto, String current, List<String> result) {
        List<CategoryTreeDto> children = dto.getChildrenItems();
        if (children.isEmpty()) {
          result.add(current);
          return;
        }
        for (CategoryTreeDto childDto : dto.getChildrenItems()) {
          String next = current + "->" + childDto.getName();
          traverse(childDto, next, result);
        }
      }
    }
    

    Goes depth first, until there are no more children, building the path in the meantime. When there are no more children add the path to the result and return (this is the ends the recursion).

    Prints

    [Pantry->Butter->Cream, Pantry->Snack, Medicine]
    

    for your example.