Question

Récemment, j'ai conversation avec un collègue au sujet de ce qui serait la façon optimale pour convertir List à Map en Java et s'il y a des avantages spécifiques de le faire.

Je veux savoir l'approche de conversion optimale et apprécierais vraiment si quelqu'un peut me guider.

Est-ce une bonne approche:

List<Object[]> results;
Map<Integer, String> resultsMap = new HashMap<Integer, String>();
for (Object[] o : results) {
    resultsMap.put((Integer) o[0], (String) o[1]);
}
Était-ce utile?

La solution

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

En supposant bien sûr que chaque élément possède une méthode getKey() qui renvoie une clé du type correspondant.

Autres conseils

, vous serez en mesure de le faire en une seule ligne en utilisant , et la classe Collectors .

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

Courte démonstration:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test{
    public static void main (String [] args){
        List<Item> list = IntStream.rangeClosed(1, 4)
                                   .mapToObj(Item::new)
                                   .collect(Collectors.toList()); //[Item [i=1], Item [i=2], Item [i=3], Item [i=4]]

        Map<String, Item> 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 String getKey(){
        return "Key-"+i;
    }

    @Override
    public String toString() {
        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 assez explicite.

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

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

Lors de l'exécution de ce code, vous obtiendrez une erreur en disant java.lang.IllegalStateException: Duplicate key 1. En effet, 1% 3 est le même que 3 à 4% et ont donc la même valeur de clé donné la touche de fonction de mappage. Dans ce cas, vous pouvez fournir un opérateur de fusion.

Voici une somme que les valeurs; (i1, i2) -> i1 + i2; qui peut être remplacé par le Integer::sum de référence de la méthode.

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

qui délivre maintenant:

0 => 9 (i.e 3 + 6)
1 => 5 (i.e 1 + 4)
2 => 7 (i.e 2 + 5)

Hope it helps! :)

Juste au cas où cette question n'est pas fermée comme doublon, la bonne réponse est d'utiliser Google Collections :

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

Depuis Java 8, réponse par @ZouZou en utilisant le collecteur de Collectors.toMap est certainement le moyen idiomatiques pour résoudre ce problème.

Et comme cela est une tâche commune, nous pouvons le faire dans un utilitaire statique.

De cette façon, la solution devient vraiment une seule ligne.

/**
 * 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 <K, T> Map<K, T> toMapBy(List<T> list,
        Function<? super T, ? extends K> mapper) {
    return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
}

Et voici comment vous l'utiliser sur un List<Student>:

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

Utilisation de Java 8, vous pouvez faire ce qui suit:

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

Value peut être un objet que vous utilisez.

A List et Map sont conceptuellement différentes. A List est une collection ordonnée d'éléments. Les articles peuvent contenir des doublons, et un élément pourraient ne pas avoir aucun concept d'un identifiant unique (clé). Un Map a des valeurs mises en correspondance avec les touches. Chaque clé ne peut pointer vers une valeur.

Par conséquent, il peut ou non en fonction des éléments de votre List, être possible de le convertir en un Map. Est-ce que les articles de votre List ont pas de doublons? Est-ce que chaque élément a une clé unique? Si oui, alors il est possible de les mettre dans un Map.

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

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

  

Il n'y a aucune garantie sur le type, la mutabilité, sérialisation, ou   fil de sécurité de la carte retournée.

Donc, si nous nous intéressons à une implémentation spécifique de l'interface par exemple Map HashMap alors nous pouvons utiliser la forme surchargée comme:

Map<String, Item> 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 que l'utilisation soit Function.identity() ou i->i est bien, mais il semble Function.identity() au lieu de i -> i pourrait sauver une mémoire par cette réponse liée .

Méthode universelle

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

public static interface ListToMapConverter<K, V> {
    public K getKey(V item);
}

Sans java-8, vous serez en mesure de le faire dans une ligne collections communes, et la classe de fermeture

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

De nombreuses solutions viennent à l'esprit, en fonction de ce que vous voulez achive:

élément Liste Chaque clé et la valeur est

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

Liste des éléments ont quelque chose à les chercher, peut-être un nom:

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

Liste des éléments ont quelque chose à les chercher, et il n'y a aucune garantie qu'ils sont uniques: Utilisez Googles MultiMaps

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

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

for( int i=0; i<list.size; i++ ) {
    map.put(i,list.get(i));
}

...

Cela dépend vraiment de ce que vous voulez achive.

Comme vous pouvez le voir dans les exemples, une carte est une application d'une clé à une valeur, alors qu'une liste est juste une série d'éléments ayant une position chacun. Donc, ils ne sont tout simplement pas automatiquement convertible.

Voici une petite méthode que j'écrit dans ce but précis. Il utilise Valider de Apache Commons.

Ne hésitez pas à utiliser.

/**
 * Converts a <code>List</code> to a map. One of the methods of the list is called to retrive
 * the value of the key to be used and the object itself from the list entry is used as the
 * objct. An empty <code>Map</code> is returned upon null input.
 * Reflection is used to retrieve the key from the object instance and method name passed in.
 *
 * @param <K> The type of the key to be used in the map
 * @param <V> 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 retrieve
 *            the key
 * @return A map of key to value instances
 * @throws IllegalArgumentException if any of the other paremeters are invalid.
 */
public static <K, V> Map<K, V> asMap(final java.util.Collection<V> coll,
        final Class<K> keyType,
        final Class<V> valueType,
        final String keyMethodName) {

    final HashMap<K, V> map = new HashMap<K, V>();
    Method method = null;

    if (isEmpty(coll)) return map;
    notNull(keyType, Messages.getString(KEY_TYPE_NOT_NULL));
    notNull(valueType, Messages.getString(VALUE_TYPE_NOT_NULL));
    notEmpty(keyMethodName, Messages.getString(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 String message =
            String.format(
                    Messages.getString(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 String message =
            String.format(
                    Messages.getString(METHOD_CALL_FAILED),
                    method,
                    valueType);
        e.fillInStackTrace();
        logger.error(message, e);
        throw new IllegalArgumentException(message, e);
    }
    return map;
}

Vous pouvez tirer parti de l'API de flux de Java 8.

public class ListToMap {

  public static void main(String[] args) {
    List<User> items = Arrays.asList(new User("One"), new User("Two"), new User("Three"));

    Map<String, User> map = createHashMap(items);
    for(String key : map.keySet()) {
      System.out.println(key +" : "+map.get(key));
    }
  }

  public static Map<String, User> createHashMap(List<User> items) {
    Map<String, User> map = items.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    return map;
  }
}

Pour plus de détails visitez: http://codecramp.com / java-8-flux-api-convert-liste-carte /

comme déjà dit, en java-8, nous avons la solution concise par les collectionneurs:

  list.stream().collect(
         groupingBy(Item::getKey)
        )

et aussi, vous pouvez imbriquer groupe multiple faisant passer un autre mode de groupingBy comme second paramètre:

  list.stream().collect(
         groupingBy(Item::getKey, groupingBy(Item::getOtherKey))
        )

De cette façon, nous aurons carte à plusieurs niveaux, comme ceci: Map<key, Map<key, List<Item>>>

A Java 8 exemple pour convertir un List<?> d'objets en Map<k, v>:

List<Hosting> 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<Integer, String> result1 = list.stream().collect(
    Collectors.toMap(Hosting::getId, Hosting::getName));

System.out.println("Result 1 : " + result1);

//example 2
Map<Integer, String> result2 = list.stream().collect(
    Collectors.toMap(x -> x.getId(), x -> x.getName()));

code copié à partir de:
https://www.mkyong.com/java8/java -8-convert-liste à carte /

Je aime la réponse de Kango_V, mais je pense qu'il est trop complexe. Je pense que cela est plus simple - peut-être trop simple. Si incliné, vous pouvez remplacer chaîne avec un marqueur générique, et le faire fonctionner pour tout type de clé.

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

public interface ListToMapConverterInterface<E> {
    public String getKeyForItem(E item);
}

Utilisé comme ceci:

        Map<String, PricingPlanAttribute> pricingPlanAttributeMap = convertListToMap( pricingPlanAttributeList,
                new ListToMapConverterInterface<PricingPlanAttribute>() {

                    @Override
                    public String getKeyForItem(PricingPlanAttribute item) {
                        return item.getFullName();
                    }
                } );

Apache Commons MapUtils.populateMap

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

MapUtils.populateMap

Disons que vous avez une liste de Pairs.

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

Et vous voulez maintenant une carte de clé de l'objet Pair du Pair.

Map<String, Pair<String, String>> map = new HashMap<>();
MapUtils.populateMap(map, pairs, new Transformer<Pair<String, String>, String>() {

  @Override
  public String transform(Pair<String, String> input) {
    return input.getKey();
  }
});

System.out.println(map);

donne une sortie:

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

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

Map<String, Pair<String, String>> map = new HashMap<>();
for (Pair<String, String> pair : pairs) {
  map.put(pair.getKey(), pair);
}
System.out.println(map);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top