web-dev-qa-db-fra.com

Java 8 liste <V> dans la carte <K, V>

Je souhaite traduire une liste d'objets en une carte à l'aide des flux et des lambdas de Java 8.

Voici comment je l'écrirais dans Java 7 et inférieur.

private Map<String, Choice> nameMap(List<Choice> choices) {
        final Map<String, Choice> hashMap = new HashMap<>();
        for (final Choice choice : choices) {
            hashMap.put(choice.getName(), choice);
        }
        return hashMap;
}

Je peux y arriver facilement avec Java 8 et Guava, mais j'aimerais savoir comment le faire sans Guava.

En goyave:

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, new Function<Choice, String>() {

        @Override
        public String apply(final Choice input) {
            return input.getName();
        }
    });
}

Et Goyave avec Java 8 lambdas.

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, Choice::getName);
}
795
Tom Cammann

Basé sur Collectors documentation c'est aussi simple que:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName,
                                              Function.identity()));
1209
zapl

Si votre clé estPASgarantie d'être unique pour tous les éléments de la liste, vous devez la convertir en Map<String, List<Choice>> au lieu d'un Map<String, Choice>

Map<String, List<Choice>> result =
 choices.stream().collect(Collectors.groupingBy(Choice::getName));
261
Ulises

Utilisez getName () comme clé et choisissez lui-même comme valeur de la carte:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
128
Ole

En voici un autre au cas où vous ne voudriez pas utiliser Collectors.toMap ()

Map<String, Choice> result =
   choices.stream().collect(HashMap<String, Choice>::new, 
                           (m, c) -> m.put(c.getName(), c),
                           (m, u) -> {});
18
Emre Colak

La plupart des réponses énumérées manquent un cas lorsque la liste contient des éléments en double . Dans ce cas, la réponse jettera IllegalStateException. Référez-vous au code ci-dessous pour gérer les doublons de liste ainsi:

public Map<String, Choice> convertListToMap(List<Choice> choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName, choice -> choice,
            (oldValue, newValue) -> newValue));
  }
15
Sahil Chhabra

Une autre option de manière simple

Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
15
Renukeswar

Par exemple, si vous souhaitez convertir des champs d’objet en mappage:

Exemple d'objet:

class Item{
        private String code;
        private String name;

        public Item(String code, String name) {
            this.code = code;
            this.name = name;
        }

        //getters and setters
    }

Et opération convertir List To Map:

List<Item> list = new ArrayList<>();
list.add(new Item("code1", "name1"));
list.add(new Item("code2", "name2"));

Map<String,String> map = list.stream()
     .collect(Collectors.toMap(Item::getCode, Item::getName));
13
Piotr R

Si vous ne craignez pas l’utilisation de bibliothèques tierces, le fichier cyclops-react lib d’AOL possède des extensions pour tous Collection JDK types, y compris Liste et Carte .

ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
10
John McClean

J'essayais de faire cela et j'ai constaté qu'en utilisant les réponses ci-dessus, lorsque j'ai utilisé Functions.identity() pour la clé de la carte, j'avais des problèmes avec l'utilisation d'une méthode locale comme this::localMethodName pour fonctionner réellement à cause de problèmes de frappe.

Functions.identity() fait réellement quelque chose à la dactylographie dans ce cas afin que la méthode ne fonctionne qu'en renvoyant Object et en acceptant un paramètre de Object

Pour résoudre ce problème, j'ai fini par abandonner Functions.identity() et à utiliser s->s à la place.

Ainsi, mon code, dans mon cas pour répertorier tous les répertoires d'un répertoire, et pour chacun d'eux, utilise le nom du répertoire comme clé de la carte, puis appelle une méthode portant le nom du répertoire et renvoie une collection d'éléments.

Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));
8
iZian

Vous pouvez créer un flux des index en utilisant un IntStream, puis les convertir en carte:

Map<Integer,Item> map = 
IntStream.range(0,items.size())
         .boxed()
         .collect(Collectors.toMap (i -> i, i -> items.get(i)));
7

Je vais écrire comment convertir une liste en carte en utilisant generics et inversion of control . Juste méthode universelle!

Peut-être nous avons liste des entiers ou liste des objets. La question est donc la suivante: que devrait être la clé de la carte?

créer une interface

public interface KeyFinder<K, E> {
    K getKey(E e);
}

utilise maintenant l'inversion de contrôle:

  static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> Finder) {
        return  list.stream().collect(Collectors.toMap(e -> Finder.getKey(e) , e -> e));
    }

Par exemple, si nous avons des objets de livre, cette classe doit choisir la clé pour la carte 

public class BookKeyFinder implements KeyFinder<Long, Book> {
    @Override
    public Long getKey(Book e) {
        return e.getPrice()
    }
}
4
grep

J'utilise cette syntaxe

Map<Integer, List<Choice>> choiceMap = 
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
4
user2069723
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
                .toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
3
Kumar Abhishek

Pour cela, il est possible d'utiliser des flux. Pour supprimer le besoin d'utiliser explicitement Collectors, il est possible d'importer toMap de manière statique (comme recommandé par Effective Java, troisième édition).

import static Java.util.stream.Collectors.toMap;

private static Map<String, Choice> nameMap(List<Choice> choices) {
    return choices.stream().collect(toMap(Choice::getName, it -> it));
}
2
Konrad Borowski

Voici la solution par StreamEx

StreamEx.of(choices).toMap(Choice::getName, c -> c);
1
user_3380739

Cela peut être fait de 2 manières. Soit personne la classe que nous allons utiliser pour le démontrer.

public class Person {

    private String name;
    private int age;

    public String getAge() {
        return age;
    }
}

Soit personnes la liste des personnes à convertir sur la carte

1.Utiliser Simple foreach et une expression Lambda sur la liste

Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));

2.Utilisation de collecteurs sur un flux défini dans la liste donnée.

 Map<Integer,List<Person>> mapPersons = 
           persons.stream().collect(Collectors.groupingBy(Person::getAge));
0
raja emani
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.
0
vaibhav
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};
    List<String> list = Arrays.asList(array);
    Map<Integer, String> map = list.stream()
            .collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {
                System.out.println("Dublicate key" + x);
                return x;
            },()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));
    System.out.println(map);

Clé publique AA {12 = ASDFASDFASDF, 7 = EEDDDAD, 4 = CCCC, 3 = BBB, 2 = AA}

0
Ajay
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));

Même sert ce but pour moi,

Map<String,Choice> map=  list1.stream().collect(()-> new HashMap<String,Choice>(), 
            (r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));
0
Rajeev Akotkar
If every new value for the same key name has to be overidden
then below will be the code :

    public Map<String, Choice> 
      convertListToMap(List<Choice> choices) {
     return choices.stream()
       .collect(Collectors.toMap(Choice::getName, 
      Function.identity(),
            (oldValue, newValue) -> newValue));
      }

If all choices have to be grouped in a list for a name then 
below will be the code:

      public Map<String, Choice> 
       convertListToMap(List<Choice> choices) {
       return choices.stream().collect(Collectors.groupingBy(Choice::getName));
  }
0
Vaneet Kataria