convert - Lista de Java 8<V> en el Mapa<K, V>
map() java 8 (17)
Quiero traducir una lista de objetos en un mapa usando las secuencias y lambdas de Java 8
Así es como lo escribiría en Java 7 y más abajo.
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;
}
Puedo lograrlo fácilmente utilizando Java 8 y Guava, pero me gustaría saber cómo hacerlo sin Guava.
En guayaba:
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();
}
});
}
Y guayaba con Java 8 lambdas.
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, Choice::getName);
}
Una opción más de manera sencilla.
Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
Aquí está la solución por StreamEx
StreamEx.of(choices).toMap(Choice::getName, c -> c);
Aquí hay otro en caso de que no quieras usar Collectors.toMap ()
Map<String, Choice> result =
choices.stream().collect(HashMap<String, Choice>::new,
(m, c) -> m.put(c.getName(), c),
(m, u) -> {});
Basado en la documentación de Collectors
es tan simple como:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName,
Function.identity()));
Es posible usar streams para hacer esto. Para eliminar la necesidad de usar Collectors
explícita, es posible importar a toMap
forma estática (según lo recomendado por Effective Java, tercera edición).
public class BookKeyFinder implements KeyFinder<Long, Book> {
@Override
public Long getKey(Book e) {
return e.getPrice()
}
}
Escribiré cómo convertir lista a mapa usando genéricos e inversión de control . ¡Solo método universal!
Tal vez tengamos lista de enteros o lista de objetos. Entonces la pregunta es la siguiente: ¿cuál debería ser la clave del mapa?
crear interfaz
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));
}
Ahora usando la inversión de control:
public interface KeyFinder<K, E> {
K getKey(E e);
}
Por ejemplo, si tenemos objetos de libro, esta clase es para elegir la clave para el mapa
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));
}
Estaba tratando de hacer esto y descubrí que, al usar las respuestas anteriores, al usar Functions.identity()
para la clave del Mapa, tuve problemas con el uso de un método local como this::localMethodName
para funcionar realmente debido a problemas de tipeo .
Functions.identity()
realidad hace algo con la escritura en este caso, por lo que el método solo funcionaría devolviendo Object
y aceptando un parámetro de Object
Para resolver esto, terminé deshaciéndome de Functions.identity()
y usando s->s
en s->s
lugar.
Por lo tanto, mi código, en mi caso, para enumerar todos los directorios dentro de un directorio, y para cada uno usa el nombre del directorio como la clave para el mapa y luego llama a un método con el nombre del directorio y devuelve una colección de elementos, se ve así:
Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));
Esto se puede hacer de 2 maneras. Que la persona sea la clase que vamos a usar para demostrarlo.
public class Person {
private String name;
private int age;
public String getAge() {
return age;
}
}
Permitir que las personas sean la lista de Personas a convertir en el mapa.
1.Utilizando Simple foreach y una expresión Lambda en la lista
Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));
2.Utilizando Collectors on Stream definido en la lista dada.
Map<Integer,List<Person>> mapPersons =
persons.stream().collect(Collectors.groupingBy(Person::getAge));
La mayoría de las respuestas enumeradas, se pierden un caso cuando la lista tiene elementos duplicados . En ese caso la respuesta arrojará la IllegalStateException
. Consulte el siguiente código para manejar los duplicados de la lista también:
public Map<String, Choice> convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName, choice -> choice,
(oldValue, newValue) -> newValue));
}
Por ejemplo, si desea convertir campos de objeto a mapear:
Objeto de ejemplo:
class Item{
private String code;
private String name;
public Item(String code, String name) {
this.code = code;
this.name = name;
}
//getters and setters
}
Y la operación convertir lista a mapa:
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));
Puede crear un flujo de los índices utilizando un IntStream y luego convertirlos en un mapa:
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
Si NO se garantiza que su clave sea única para todos los elementos de la lista, debe convertirla en un Map<String, List<Choice>>
lugar de un Map<String, Choice>
Map<String, List<Choice>> result =
choices.stream().collect(Collectors.groupingBy(Choice::getName));
Si no le importa usar bibliotecas de terceros, la biblioteca cyclops-react ciclops de AOL (divulgación, contribuyo) tiene extensiones para todos los tipos de colecciones JDK , incluyendo List y Map .
ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
Use getName () como la clave y la elección en sí misma como el valor del mapa:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Yo uso esta sintaxis
Map<Integer, List<Choice>> choiceMap =
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
.toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));
Incluso sirve para este propósito para mí,
Map<String,Choice> map= list1.stream().collect(()-> new HashMap<String,Choice>(),
(r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));