7
votes

Comment créer List to Map au lieu de Map >?

J'ai rencontré le cas où j'ai besoin de convertir List en Map et la seule solution que je peux trouver est de savoir comment faire Map > .

La classe elle-même ressemble à la manière suivante (j'ai omis les getters / setters et les constructeurs):

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

Je veux mapper tous les livres avec certaines clés uniques, donc la probabilité de duplication est soit négligeable soit 0.

J'ai essayé de le faire de cette façon:

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

Cela fonctionne mais cela a l'air moche, difficilement lisible et pas très agréable à avoir dans la base de code car cela peut dérouter mes collègues. Existe-t-il un meilleur moyen java 8 d’obtenir le même résultat?


0 commentaires

3 Réponses :


4
votes

Vous n'avez pas besoin de regrouper vos livres si vous êtes sûr que les clés sont uniques.

Map<String, Book> booksByAsinAndTitle = books.stream()
    .collect(Collectors.toMap(book -> book.getAsin() + "||" + book.getTitle(), x -> x));


0 commentaires

7
votes

Utilisez toMap au lieu de groupingBy:

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

Si la clé selon laquelle vous groupez est unique, il n'y a aucune raison de utilisez groupingBy.

Si votre clé n'est peut-être pas unique et que vous voulez toujours que la Map contienne la première valeur correspondant à une clé donnée, ajoutez un fonction de fusion:

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


5 commentaires

Y aura-t-il une différence si ma clé ne sera pas unique et que je déciderai de prendre le premier élément?


@DmytroChasovskyi vous devrez ajouter une fonction de fusion dans ce cas


Eh bien, j'y pensais en postant ma réponse aussi. (a, b) -> a garantirait-il .get (0) ?


@nullpointer bien, je pense que c'est plus correct que .get (0), puisque groupingBy ne dit rien sur l'ordre des éléments dans la liste d'un groupe donné. .get (0) peut ou non retourner le premier livre (selon l'ordre de la liste d'origine) qui correspond à une clé donnée.


@Eran Apparemment, groupingBy préserve l'ordre. stackoverflow.com/questions/39172981/… < / a>



2
votes

Une représentation plus simple de la même chose en utilisant Map.putIfAbsent et forEach seraient:

Function<Book, String> primaryKey = book -> book.getAsin() + "||" + book.getTitle();
Map<String, Book> booksByAsinAndTitle = new HashMap<>();
books.forEach(book -> booksByAsinAndTitle.putIfAbsent(primaryKey.apply(book), book));

Remarque : Cela garantit que le premier livre trouvé sur une clé reste dans la carte.


0 commentaires