Pregunta

Recientemente tengo conversación con un colega sobre cuál sería la mejor manera de convertir a List Map en Java y si hay ningún beneficio específico de hacerlo.

Quiero saber enfoque conversión óptima y apreciaría realmente si alguien me puede orientar.

¿Es bueno este enfoque:

List<Object[]> results;
Map<Integer, String> resultsMap = new HashMap<Integer, String>();
for (Object[] o : results) {
    resultsMap.put((Integer) o[0], (String) o[1]);
}
¿Fue útil?

Solución

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

asumiendo por supuesto que cada artículo tiene un método getKey() que devuelve una clave del tipo adecuado.

Otros consejos

, usted será capaz de hacer esto en una línea usando arroyos , y la href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html"> Collectors clase

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

breve demostración:

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 + "]";
    }
}

Salida:

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

Como se señaló en los comentarios, se puede utilizar en lugar de Function.identity() item -> item, aunque lo encuentro i -> i en lugar explícita.

Y para ser nota completa que se puede utilizar un operador binario si su función no es biyectiva. Por ejemplo vamos a considerar este List y la función de mapeo que para un valor int, calcular el resultado del mismo 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));

Cuando se ejecuta este código, se obtendrá un error que dice java.lang.IllegalStateException: Duplicate key 1. Esto se debe a 1% 3 es el mismo que 4% 3 y por lo tanto tiene el mismo valor de clave dada la función de asignación de teclas. En este caso, se puede proporcionar un operador de combinación.

Aquí hay uno que suma los valores; (i1, i2) -> i1 + i2; que puede ser reemplazado con el Integer::sum referencia método.

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

que ahora da salida:

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

Hope que ayuda! :)

Sólo en caso de esta pregunta no es cerrado como un duplicado, la respuesta correcta es utilizar Google Colecciones :

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

Desde Java 8, la respuesta por @ZouZou utilizando el colector Collectors.toMap es sin duda la forma idiomática para resolver este problema.

Y ya que esta es una tarea tan común, podemos convertirlo en una herramienta estática.

De esta forma la solución se convierte realmente en una sola línea.

/**
 * 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()));
}

Y así es como se usaría en una List<Student>:

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

Uso de Java 8 se puede hacer lo siguiente:

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

Value puede ser cualquier objeto que utilice.

A List y Map son conceptualmente diferente. Un List es una colección ordenada de elementos. Los artículos pueden contener duplicados, y un elemento que no tenga ningún concepto de un identificador único (clave). Un Map tiene valores asignados a las teclas. Cada tecla sólo puede apuntar a un valor.

Por lo tanto, en función de los elementos de su List, que puede o no puede ser posible para convertirlo en un Map. ¿Tiene elementos de su List no tienen duplicados? ¿Cada artículo tiene una clave única? Si es así, entonces es posible ponerlos en una Map.

También hay una forma sencilla de hacer esto usando Maps.uniqueIndex (...) de Google bibliotecas

Alexis ya ha publicado una respuesta en Java 8 utilizando toMap(keyMapper, valueMapper) método. Como por doc para este método de aplicación:

  

No hay garantías en cuanto al tipo, la mutabilidad, serializabilidad, o   hilo de seguridad del mapa devuelto.

Así que en caso de que estén interesados ??en una implementación específica de la interfaz, por ejemplo Map HashMap entonces podemos utilizar la versión sobrecargada como:

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

Aunque el uso de cualquiera Function.identity() o i->i está bien, pero parece Function.identity() en lugar de i -> i podría ahorrar algo de memoria de acuerdo con esta respuesta relacionada .

método universal

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);
}

Sin java-8, usted será capaz de hacer esto en las colecciones de una línea Commons, y la clase de cierre

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);
        }
    });
}};

Muchas de las soluciones vienen a la mente, dependiendo de lo que desea achive:

Cada elemento de la lista es clave y el valor

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

Los elementos de la lista tienen algo para mirar hacia arriba, tal vez un nombre:

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

Los elementos de la lista tienen algo para mirar hacia arriba, y no hay garantía de que son únicos: Uso de Google Multimapas

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

Dar a todos los elementos de la posición como una clave:

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

...

Realmente depende de lo que quiere achive.

Como se puede ver en los ejemplos, un mapa es una asignación de una clave a un valor, mientras que la lista es sólo una serie de elementos que tienen una posición de cada uno. Por lo que simplemente no son automáticamente convertible.

He aquí un método poco escribí precisamente para este propósito. Utiliza Validar de Apache Commons.

Siéntase libre de usarlo.

/**
 * 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;
}

Se puede aprovechar la API de Secuencia 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;
  }
}

Para más detalles visita: http://codecramp.com / java-8-corrientes-api-convertir-list-mapa /

como ya se ha dicho, en java-8 tenemos la solución concisa por Collectors:

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

y también, se pueden agrupar múltiples nido pasar otro método groupingBy como segundo parámetro:

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

De este modo, tendremos un mapa de niveles múltiples, así: Map<key, Map<key, List<Item>>>

A Java 8 ejemplo para convertir una List<?> de objetos en un 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()));

Código copiada de:
https://www.mkyong.com/java8/java -8-convertir-lista-para-mapa /

Me gusta la respuesta de Kango_V, pero creo que es demasiado complejo. Creo que esto es más simple - tal vez demasiado simple. Si inclinado, puede reemplazar la secuencia con un marcador genérico, y hacer que funcione para cualquier tipo de claves.

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);
}

Se utiliza como esto:

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

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

Apache Commons MapUtils.populateMap

Si usted no utiliza Java 8 y usted no desea utilizar un bucle explícito por alguna razón, trate MapUtils.populateMap de Apache Commons.

MapUtils.populateMap

Supongamos que tiene una lista de Pairs.

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

Y ahora quiere un mapa de las llaves de su Pair al objeto 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);

da salida:

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

Una vez dicho esto, un bucle for es quizá más fácil de entender. (Esto siguiente da la misma salida):

Map<String, Pair<String, String>> map = new HashMap<>();
for (Pair<String, String> pair : pairs) {
  map.put(pair.getKey(), pair);
}
System.out.println(map);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top