Java: comment convertir la liste en carte

Récemment, j’ai discuté avec un collègue de ce que serait le moyen optimal de convertir List to Map en Java et si cela présentait des avantages spécifiques.

Je veux connaître l’approche de conversion optimale et j’apprécierais vraiment que quelqu’un puisse me guider.

Est-ce une bonne approche:

 List results; Map resultsMap = new HashMap(); for (Object[] o : results) { resultsMap.put((Integer) o[0], (Ssortingng) o[1]); } 

 List list; Map map = new HashMap(); for (Item i : list) map.put(i.getKey(),i); 

En supposant bien sûr que chaque élément a une méthode getKey() qui renvoie une clé du type approprié.

Avec java-8 , vous pourrez le faire en une seule ligne en utilisant des stream et la classe Collectors .

 Map map = list.stream().collect(Collectors.toMap(Item::getKey, item -> item)); 

Courte démo:

 import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Test{ public static void main (Ssortingng [] args){ List list = IntStream.rangeClosed(1, 4) .mapToObj(Item::new) .collect(Collectors.toList()); //[Item [i=1], Item [i=2], Item [i=3], Item [i=4]] Map map = list.stream().collect(Collectors.toMap(Item::getKey, item -> item)); map.forEach((k, v) -> System.out.println(k + " => " + v)); } } class Item { private final int i; public Item(int i){ this.i = i; } public Ssortingng getKey(){ return "Key-"+i; } @Override public Ssortingng toSsortingng() { return "Item [i=" + i + "]"; } } 

Sortie:

 Key-1 => Item [i=1] Key-2 => Item [i=2] Key-3 => Item [i=3] Key-4 => Item [i=4] 

Comme indiqué dans les commentaires, vous pouvez utiliser Function.identity() au lieu de item -> item , bien que je trouve i -> i plutôt explicite.

Et pour être complet, notez que vous pouvez utiliser un opérateur binary si votre fonction n’est pas bijective. Par exemple, considérons cette List et la fonction de mappage que pour une valeur int, calculons le résultat modulo 3:

 List intList = Arrays.asList(1, 2, 3, 4, 5, 6); Map map = intList.stream().collect(toMap(i -> Ssortingng.valueOf(i % 3), i -> i)); 

Lorsque vous exécutez ce code, vous obtenez une erreur en indiquant java.lang.IllegalStateException: Duplicate key 1 . En effet, 1% 3 est identique à 4% 3 et a donc la même valeur de clé compte tenu de la fonction de mappage de clé. Dans ce cas, vous pouvez fournir un opérateur de fusion.

En voici un qui additionne les valeurs; (i1, i2) -> i1 + i2; cela peut être remplacé par la méthode référence Integer::sum .

 Map map = intList.stream().collect(toMap(i -> Ssortingng.valueOf(i % 3), i -> i, Integer::sum)); 

qui produit maintenant:

 0 => 9 (ie 3 + 6) 1 => 5 (ie 1 + 4) 2 => 7 (ie 2 + 5) 

J’espère que cela aide! 🙂

Juste au cas où cette question ne serait pas fermée en double, la bonne réponse est d’utiliser Google Collections :

 Map mappedRoles = Maps.uniqueIndex(yourList, new Function() { public Ssortingng apply(Role from) { return from.getName(); // or something else }}); 

Depuis Java 8, la réponse à @ZouZou en utilisant le collecteur Collectors.toMap est certainement la manière idiomatique de résoudre ce problème.

Et comme c’est une tâche si courante, nous pouvons en faire un utilitaire statique.

De cette façon, la solution devient véritablement un one-liner.

 /** * Returns a map where each entry is an item of {@code list} mapped by the * key produced by applying {@code mapper} to the item. * * @param list the list to map * @param mapper the function to produce the key from a list item * @return the resulting map * @throws IllegalStateException on duplicate key */ public static  Map toMapBy(List list, Function mapper) { return list.stream().collect(Collectors.toMap(mapper, Function.identity())); } 

Et voici comment l’utiliser sur une List :

 Map studentsById = toMapBy(students, Student::getId); 

Une List et une Map sont conceptuellement différentes. Une List est une collection ordonnée d’éléments. Les éléments peuvent contenir des doublons et un élément peut ne pas avoir de concept d’identificateur unique (clé). Une Map a des valeurs mappées sur des clés. Chaque touche ne peut pointer que sur une valeur.

Par conséquent, en fonction des éléments de votre List , il peut être possible ou non de le convertir en Map . Les éléments de votre List n’ont-ils pas de doublons? Chaque article a-t-il une clé unique? Si c’est le cas, il est possible de les placer dans une Map .

Il y a aussi un moyen simple de le faire en utilisant Maps.uniqueIndex (…) des bibliothèques de Google Guava

Méthode universelle

 public static  Map listAsMap(Collection sourceList, ListToMapConverter converter) { Map newMap = new HashMap(); for (V item : sourceList) { newMap.put( converter.getKey(item), item ); } return newMap; } public static interface ListToMapConverter { public K getKey(V item); } 

En utilisant Java 8, vous pouvez faire ce qui suit:

 Map result= results .stream() .collect(Collectors.toMap(Value::getName,Function.identity())); 

Value peut être n’importe quel object que vous utilisez.

Sans java-8, vous pourrez le faire dans une seule collection Commons, et dans la classe Closure

 List list; @SuppressWarnings("unchecked") Map map = new HashMap>(){{ CollectionUtils.forAllDo(list, new Closure() { @Override public void execute(Object input) { Item item = (Item) input; put(i.getKey(), item); } }); }}; 

Alexis a déjà publié une réponse dans Java 8 en utilisant la méthode toMap(keyMapper, valueMapper) . Selon la documentation pour cette implémentation de la méthode:

Il n’y a aucune garantie sur le type, la mutabilité, la sérialisation, ou la sécurité des threads de la carte renvoyée.

Donc, si nous sums intéressés par une implémentation spécifique de l’interface Map , par exemple HashMap nous pouvons utiliser le formulaire surchargé comme:

 Map map2 = itemList.stream().collect(Collectors.toMap(Item::getKey, //key for map Function.identity(), // value for map (o,n) -> o, // merge function in case of conflict with keys HashMap::new)); // map factory - we want HashMap and not any Map implementation 

Bien qu’utiliser soit Function.identity() soit i->i soit correct mais il semble que Function.identity() au lieu de i -> i pourrais économiser de la mémoire selon cette réponse .

De nombreuses solutions vous viennent à l’esprit, en fonction de ce que vous souhaitez réaliser:

Chaque élément de la liste est la clé et la valeur

 for( Object o : list ) { map.put(o,o); } 

Les éléments de la liste ont quelque chose à rechercher, peut-être un nom:

 for( MyObject o : list ) { map.put(o.name,o); } 

Les éléments de la liste ont quelque chose à rechercher, et rien ne garantit qu’ils soient uniques: Utiliser MultiMaps Googles

 for( MyObject o : list ) { multimap.put(o.name,o); } 

Donner à tous les éléments la position comme clé:

 for( int i=0; i 

...

Cela dépend vraiment de ce que vous voulez réaliser.

Comme vous pouvez le voir dans les exemples, une carte est une correspondance entre une clé et une valeur, tandis qu’une liste n’est qu’une série d’éléments ayant chacun une position. Ils ne sont donc pas automatiquement convertibles.

Voici une petite méthode que j’ai écrite exactement pour cela. Il utilise Validate de Apache Commons.

Sentez-vous libre de l’utiliser.

 /** * Converts a List to a map. One of the methods of the list is called to resortingve * the value of the key to be used and the object itself from the list entry is used as the * objct. An empty Map is returned upon null input. * Reflection is used to resortingeve the key from the object instance and method name passed in. * * @param  The type of the key to be used in the map * @param  The type of value to be used in the map and the type of the elements in the * collection * @param coll The collection to be converted. * @param keyType The class of key * @param valueType The class of the value * @param keyMethodName The method name to call on each instance in the collection to resortingeve * the key * @return A map of key to value instances * @throws IllegalArgumentException if any of the other paremeters are invalid. */ public static  Map asMap(final java.util.Collection coll, final Class keyType, final Class valueType, final Ssortingng keyMethodName) { final HashMap map = new HashMap(); Method method = null; if (isEmpty(coll)) return map; notNull(keyType, Messages.getSsortingng(KEY_TYPE_NOT_NULL)); notNull(valueType, Messages.getSsortingng(VALUE_TYPE_NOT_NULL)); notEmpty(keyMethodName, Messages.getSsortingng(KEY_METHOD_NAME_NOT_NULL)); try { // return the Method to invoke to get the key for the map method = valueType.getMethod(keyMethodName); } catch (final NoSuchMethodException e) { final Ssortingng message = Ssortingng.format( Messages.getSsortingng(METHOD_NOT_FOUND), keyMethodName, valueType); e.fillInStackTrace(); logger.error(message, e); throw new IllegalArgumentException(message, e); } try { for (final V value : coll) { Object object; object = method.invoke(value); @SuppressWarnings("unchecked") final K key = (K) object; map.put(key, value); } } catch (final Exception e) { final Ssortingng message = Ssortingng.format( Messages.getSsortingng(METHOD_CALL_FAILED), method, valueType); e.fillInStackTrace(); logger.error(message, e); throw new IllegalArgumentException(message, e); } return map; } 

Vous pouvez exploiter l’API de stream de Java 8.

 public class ListToMap { public static void main(Ssortingng[] args) { List items = Arrays.asList(new User("One"), new User("Two"), new User("Three")); Map map = createHashMap(items); for(Ssortingng key : map.keySet()) { System.out.println(key +" : "+map.get(key)); } } public static Map createHashMap(List items) { Map map = items.stream().collect(Collectors.toMap(User::getId, Function.identity())); return map; } } 

Pour plus de détails, visitez: http://codecramp.com/java-8-streams-api-convert-list-map/

Un exemple Java 8 pour convertir une List objects en une Map :

 List list = new ArrayList<>(); list.add(new Hosting(1, "liquidweb.com", new Date())); list.add(new Hosting(2, "linode.com", new Date())); list.add(new Hosting(3, "digitalocean.com", new Date())); //example 1 Map result1 = list.stream().collect( Collectors.toMap(Hosting::getId, Hosting::getName)); System.out.println("Result 1 : " + result1); //example 2 Map result2 = list.stream().collect( Collectors.toMap(x -> x.getId(), x -> x.getName())); 

Code copié à partir de:
https://www.mkyong.com/java8/java-8-convert-list-to-map/

J’aime la réponse de Kango_V, mais je pense que c’est trop complexe. Je pense que c’est plus simple – peut-être trop simple. Si vous êtes incliné, vous pouvez remplacer Ssortingng par un marqueur générique et le faire fonctionner pour tout type de clé.

 public static  Map convertListToMap(Collection sourceList, ListToMapConverterInterface converterInterface) { Map newMap = new HashMap(); for( E item : sourceList ) { newMap.put( converterInterface.getKeyForItem( item ), item ); } return newMap; } public interface ListToMapConverterInterface { public Ssortingng getKeyForItem(E item); } 

Utilisé comme ceci:

  Map pricingPlanAtsortingbuteMap = convertListToMap( pricingPlanAtsortingbuteList, new ListToMapConverterInterface() { @Override public Ssortingng getKeyForItem(PricingPlanAtsortingbute item) { return item.getFullName(); } } ); 

Apache Commons MapUtils.populateMap

Si vous n’utilisez pas Java 8 et que vous ne souhaitez pas utiliser une boucle explicite pour une raison quelconque, essayez MapUtils.populateMap partir d’Apache Commons.

MapUtils.populateMap

Disons que vous avez une liste de Pair .

 List> pairs = ImmutableList.of( new ImmutablePair<>("A", "aaa"), new ImmutablePair<>("B", "bbb") ); 

Et vous voulez maintenant une carte de la clé de la Pair object Pair .

 Map> map = new HashMap<>(); MapUtils.populateMap(map, pairs, new Transformer, Ssortingng>() { @Override public Ssortingng transform(Pair input) { return input.getKey(); } }); System.out.println(map); 

donne sortie:

 {A=(A,aaa), B=(B,bbb)} 

Cela étant dit, une boucle for est peut-être plus facile à comprendre. (Ce qui suit donne la même sortie):

 Map> map = new HashMap<>(); for (Pair pair : pairs) { map.put(pair.getKey(), pair); } System.out.println(map); 

Voici les moyens les plus courants de convertir une liste en carte en Java:

Java 7 et avant

C’est la méthode traditionnelle par laquelle nous parcourons la liste et remplissons un hashmap à partir des éléments de la liste.

 public static Map listToHashmapJava7Below(List students) { Map studentsMap = new HashMap(); for(Student student : students) { studentsMap.put(student.getId(), student.getName()); } return studentsMap; } 

Java 8

En utilisant stream () et Collectors.toMap () fournis par Java 8, vous pouvez convertir une liste en carte comme suit:

 public static Map listToHashmapJava8(List students) { Map studentsMap = students.stream().collect(Collectors.toMap(Student :: getId, Student :: getName)); return studentsMap; } 

Référence: Java – Convertir la liste en carte