Search code examples
javajava-stream

How to sort the results of Collectors.groupingBy in the same stream statement?


Code:

public class Main {

public static void main(String[] args) {

    List<Book> books = new ArrayList<>();

    books = List.of(new Book("Aus dem All", "Horror", "Stephen King"),
            new Book("Evil", "Horror", "Stephen King"),
            new Book("See House", "Fantasy", "Anthony Marc"),
            new Book("Scream", "Thriller", "Larissa Vega"),
            new Book("Killer Hamster", "Horror", "Stephen King"),
            new Book("Who killed Ben?", "Thriller", "Stephen King"),
            new Book("The Hills have Eyes", "Horror", "Manfred Meyer"),
            new Book("Lost Love", "Drama", "Benedikt Hold"),
            new Book("Office Killer", "Horror", "Stephen King"));

    // group list of books by author

    Map<String, List<String>> collect = books.stream()
            .collect(Collectors.groupingBy(Book::getAuthor,
                     Collectors.mapping(Book::getTitle, Collectors.toList()))
    );

    System.out.println(collect);
}

}

collect result: {Benedikt Hold=[Lost Love], Manfred Meyer=[The Hills have Eyes], Larissa Vega=[Scream], Anthony Marc=[See House], Stephen King=[Aus dem All, Evil, Killer Hamster, Who killed Ben?, Office Killer]}

I want the map key sorted by authors. "Anthony Marc" should be first then "Benedikt Hold" and so on..

i tried to sort the stream before the terminal operation collect with:

.sorted((b1,b2) -> b1.getAuthor().compareTo(b2.getAuthor()))

but the result is the same.

Have anyone a idea how i sort the results in my stream statement? (i dont want sort it after the stream. i want sort it IN my stream statement)


Solution

  • The map collected by groupingBy is not guaranteed to be a sorted map. It could be, for example a HashMap, which by its very nature has no order in its key value pairs.

    You can specify the type of map you want groupingBy to collect into:

    Collectors.groupingBy(Book::getAuthor,
                     TreeMap::new,
                     Collectors.mapping(Book::getTitle, Collectors.toList()))
    

    The default constructor of TreeMap creates a TreeMap that orders the key value pairs by the natural order the keys, which seems to be the order you want here.