reales - ¿Cómo convertir la Lista<V> en Mapa<K, Lista<V>>, con flujos de Java 8 y proveedores personalizados de Lista y Mapa?
manual programacion android (2)
Es fácil convertir la List<V>
en el Map<K, List<V>>
. Por ejemplo:
public Map<Integer, List<String>> getMap(List<String> strings) {
return
strings.stream()
.collect(Collectors.groupingBy(String::length));
}
Pero quiero hacerlo con mis propios proveedores de List
y Map
.
Se me ha ocurrido esto:
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream()
.collect(Collectors.toMap(
String::length,
item -> {List<String> list = new ArrayList<>(); list.add(item); return list;},
(list1, list2) -> {list1.addAll(list2); return list1;},
HashMap::new));
}
Pregunta: ¿Existe una manera más fácil, menos verbosa o más eficiente de hacerlo? Por ejemplo, algo como esto (que no funciona):
return strings.stream()
.collect(Collectors.toMap(
String::length,
ArrayList::new,
HashMap::new));
¿Y qué pasa si solo necesito definir el proveedor de la List
, pero no el proveedor del Map
?
Tuve una situación similar. Lo resolví como
Map<String, List<Object>> map = stringList.stream().collect(Collectors.toMap(str -> str, str -> populateList(str)));
Y populateList()
es:
private List<Object> populateList(final String str) {
...
....
List<Object> list = // dao.get(str);
return list;
}
Usted podría tener lo siguiente:
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream().collect(
Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new))
);
}
El groupingBy recopiladoresBy groupingBy se puede utilizar para especificar qué tipo de mapa se desea, pasándole un proveedor del mapa deseado para mapFactory
. Luego, el colector en sentido descendente, que se utiliza para recopilar elementos agrupados en la misma clave, es toCollection(collectionFactory)
, que permite recopilar en una colección obtenida del proveedor dado.
Esto asegura que el mapa devuelto sea un HashMap
y que las listas, en cada valor, sean ArrayList
. Tenga en cuenta que si desea devolver implementaciones específicas de mapas y recopilaciones, es probable que desee que el método también devuelva esos tipos específicos, de modo que pueda usar sus propiedades.
Si solo desea especificar un proveedor de colecciones y seguir groupingBy
por mapa predeterminado, solo puede omitir el proveedor en el código anterior y usar la sobrecarga de dos argumentos :
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream().collect(
Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new))
);
}
Como nota al margen, podría tener un método genérico para eso:
public <K, V, C extends Collection<V>, M extends Map<K, C>> M getMap(List<V> list,
Function<? super V, ? extends K> classifier, Supplier<M> mapSupplier, Supplier<C> collectionSupplier) {
return list.stream().collect(
Collectors.groupingBy(classifier, mapSupplier, Collectors.toCollection(collectionSupplier))
);
}
La ventaja de esta declaración es que ahora puede usarla para tener HashMap
específico de ArrayList
s como resultado, o LinkedHashMap
de LinkedLists
s, si la persona que llama lo desea:
HashMap<Integer, ArrayList<String>> m = getMap(Arrays.asList("foo", "bar", "toto"),
String::length, HashMap::new, ArrayList::new);
LinkedHashMap<Integer, LinkedList<String>> m2 = getMap(Arrays.asList("foo", "bar", "toto"),
String::length, LinkedHashMap::new, LinkedList::new);
pero, en ese momento, puede ser más sencillo usar directamente la groupingBy
por el código ...