2

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?

2
  • Build a Map keyed by id and decide whether a secondary group should update values or not, in case the multiple definitions of the same group has different values. Commented Oct 1, 2018 at 21:21
  • 1
    docs.oracle.com/javase/8/docs/api/java/util/stream/… Commented Oct 1, 2018 at 21:22

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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);.

2 Comments

With this approach, you are modifying the favorite lists of the original favorite groups, you need to make a copy instead of using function identity.
@FedericoPeraltaSchaffner I had flagged this in my answer and provided a solution to that too. I think you didn't see the comment inside the code block.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.