Phoenix_uy
Phoenix_uy

Reputation: 3294

Java 8 group list of objects with list inside

I've two objects in my java project that are something like this:

FavoriteGroup
- int id
- string userId
- string name
- List<Favorite> favorites

and

Favorite
- int id
- int groupId
- string title
- string path

Now, I've a List of items that may repeat the groups. Do I have a way to group that list in a way that for each FavoriteGroup I've all my Favorite list joined?

More graphical explanation: I've:

[{ 
    id: 1,
    userId: 1,
    name: "Group one",
    favorites: [{
       id: 100,
       groupId: 1,
       title: "Favorite 1",
       path: "path 1" 
    }]

 },
{ 
    id: 1,
    userId: 1,
    name: "Group one",
    favorites: [{
       id: 200,
       groupId: 1,
       title: "Favorite 2",
       path: "path 2" 
    }]

 },
{ 
    id: 2,
    userId: 1,
    name: "Group two",
    favorites: [{
       id: 300,
       groupId: 2,
       title: "Favorite 3",
       path: "path 3" 
    }]

 }]

And I need:

[{ 
        id: 1,
        userId: 1,
        name: "Group one",
        favorites: [{
           id: 100,
           groupId: 1,
           title: "Favorite 1",
           path: "path 1" 
        },
       {
           id: 200,
           groupId: 1,
           title: "Favorite 2",
           path: "path 2" 
        }]

     },
    { 
        id: 2,
        userId: 1,
        name: "Group two",
        favorites: [{
           id: 300,
           groupId: 2,
           title: "Favorite 3",
           path: "path 3" 
        }]

     }]

What's the best way to do this? using for loop iterations or maybe grouping java 8 stream functions?

Upvotes: 2

Views: 5803

Answers (2)

Kartik
Kartik

Reputation: 7907

Try this:-

favoriteGroups.stream()
        .collect(Collectors.toMap(FavoriteGroup::getId, Function.identity(), (fg1, fg2) -> {
            //This will modify the original object(s). If you don't want that, then you'll have to clone the object and set favorites.
            fg1.setFavorites(Stream.concat(fg1.getFavorites().stream(), fg2.getFavorites().stream())
                    .collect(Collectors.toList()));
            return fg1;
        }))
        .values();

This will return an object of type Collection<FavoriteGroup>, which you can iterate over. If you want to convert it back to List, you can do List<FavoriteGroup> list = new ArrayList<>(favoriteGroupsCollection);.

Upvotes: 0

Ravindra Ranwala
Ravindra Ranwala

Reputation: 21124

I would rather do it like so,

private static final String DELIMITER = "-";

Map<String, List<Favorite>> favsByGroup = favGroups.stream()
       .collect(Collectors.groupingBy(g -> g.getId() + DELIMITER + g.getUserId() + DELIMITER + g.getName(),
            Collectors.flatMapping(fg -> fg.getFavorites().stream(), Collectors.toList())));
List<FavoriteGroup> mergedFavoriteGroups = favsByGroup.entrySet().stream()
    .map(e -> new FavoriteGroup(Integer.parseInt(e.getKey().split(DELIMITER)[0]),
        e.getKey().split(DELIMITER)[1], e.getKey().split(DELIMITER)[2], e.getValue()))
    .collect(Collectors.toList());

First create a map taking the concatenated Id, userId and name properties of FavoriteGroup as the key and the List of Favorite instances as the value. Then for each entry in the map, I'll create a new FavoriteGroup by decoding the key and passing the values as it is. As a final step collect the resulting objects to a container.

Upvotes: 2

Related Questions