How to create List<T> to Map<String, T> instead of Map<String, List<T>>?

  • A+

I encountered with the case when I need to convert List<Book> to Map<String, Book> and the only solutions I can find is how to do Map<String, List<Book>>.

The class itself looks the following way (I ommitted getters/setters and constructors):

public class Book {     private String asin;     private String author;     private String title; } 

I want to map all books by certain unique keys, so probability of duplication is either neglectable or 0.

I tried to do it this way:

    Map<String, Book> booksByAsinAndTitle =         .collect(Collectors.groupingBy((book) -> book.getAsin() + "||" + book.getTitle()))         .entrySet()         .stream()         .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().get(0))); 

It works but it looks ugly, hardly readable and not very nice to have in the codebase because it may confuse my colleagues. Is there any better way java 8 way to achieve the same result?


Use toMap instead of groupingBy:

Map<String, Book> booksByAsinAndTitle =          .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),                                    Function.identity())); 

If the key according to which you are grouping is unique, there's no reason to use groupingBy.

If your key may not be unique, and you still want the Map to contain the first value matching a given key, add a merge function:

Map<String, Book> booksByAsinAndTitle =          .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),                                    Function.identity()),                                    (a,b) -> a); 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: