Home > Blockchain >  Can I obtaine a List of objects with a stream?
Can I obtaine a List of objects with a stream?

Time:03-25

I have a list of objects:

public class User{
String name;
String hobby;
}

And concrete

User1 = { name1, hobby1 }
User2 = { name1, hobby2 }
User3 = { name2, hobby1 }
User4 = { name1, hobby3 }

I want to obtain now an object containing :

public class HobbySortedByUserName{
String name;
List<String> hobbys;
}

Result will be:

List<HobbySortedByUserName> list;
First element:
{ "name1", [ "hobby1", "hobby2", "hobby3"]}
Seconde element:
{ "name2", [ "hobby1" ])

If I use streams, I can obtain this as a Map<String, List < String > > . But I want to have a List of Objects and not a map.

I can do a new Stream from the map, and map each value in the object, but I don't think that a good practise, as I do 2 times a Stream.

How can I achieve them?

CodePudding user response:

You can convert your map to list with Map api like

map.entrySet()
            .stream().map(e -> new YourDesiredObject<>(e.getKey(), e.getValue()))
            .collect(Collectors.toList());

CodePudding user response:

You could do something like this:

List<UserHobbies> grouped = users.stream()
        .sorted(Comparator.comparing(User::getName))
        .collect(LinkedList::new,
                (list, user) -> {
                    if (list.isEmpty() || !list.getLast().getName().equals(user.getName())) {
                        list.add(new UserHobbies(user.getName()));
                    }
                    list.getLast().addHobby(user.getHobby());
                },
                (list1, list2) -> {
                    if (list1.size() > 0 && list2.size() > 0
                            && list1.getLast().getName().equals(list2.getFirst().getName())) {
                        list1.getLast().getHobbies().addAll(list2.removeFirst().getHobbies());
                    }
                    list1.addAll(list2);
                });

But honestly, using a map, or even a simple loop, would be much cleaner and probably more efficient.

CodePudding user response:

You want to (1) group User objects by name, which internally utilizes Map, as well as you want to (2) present Map-like data as List. I am afraid the Stream API is not so powerful to satisfy both your requirements using single stream.

You can directly create result object (BTW please rename your custom class to something specific, the name Object attracts downvotes to otherwise good question) in downstream collector of groupingBy but still you need extra stream to flatten map entry values into result list:

listOfUsers.stream()
        .collect(groupingBy(User::getName, collectingAndThen(toList(), l -> new YourObject(l.get(0).getName(), l.stream().map(User::getHobby).collect(toList())))))
        .values().stream()
        .collect(toList());

which is code I definitely don't want to get for code review.


Original answer (no longer valid, thanks to @shmosel):

Just transform map entries:

listOfUsers.stream()
        .collect(groupingBy(User::getName, mapping(User::getHobby, toList())))
        // you are here now ^
        .entrySet().stream()
        .map(entry -> new YourObject(entry.getKey(), entry.getValue()))
        .collect(toList());

CodePudding user response:

You can convert the values of map to a list

  •  Tags:  
  • java
  • Related