如何使用Java 8流以及自定义列表和地图供应商将List<V>转换为Map<K,List<V>>?

2022-09-01 04:27:56

很容易转换为.例如:List<V>Map<K, List<V>>

public Map<Integer, List<String>> getMap(List<String> strings) {
   return
      strings.stream()
             .collect(Collectors.groupingBy(String::length));
}

但我想和我自己的供应商一起做。ListMap

我想出了这个:

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

问题:有没有更简单,更不冗长或更有效的方法?例如,像这样的东西(这不起作用):

return strings.stream()
      .collect(Collectors.toMap(
            String::length,
            ArrayList::new,                    
            HashMap::new));

如果我只需要定义供应商,而不需要定义供应商,该怎么办?ListMap


答案 1

您可以拥有以下内容:

public Map<Integer, List<String>> getMap(List<String> strings) {
    return strings.stream().collect(
      Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new))
    );
}

收集器分组By(分类器,mapFactory,下游)可用于指定所需的地图类型,方法是将其传递给所需的地图的供应商。然后,用于收集分组到同一键的元素的下游收集器是 toCollection(collectionFactory),它能够收集到从给定供应商处获得的集合中。mapFactory

这可确保返回的映射为 a,并且每个值中的列表为 。请注意,如果要返回 map 和集合的特定实现,则很可能希望该方法也返回这些特定类型,以便可以使用其属性。HashMapArrayList

如果您只想指定集合供应商,并保留默认映射,则可以在上面的代码中省略供应商,并使用两个参数重载groupingBy

public Map<Integer, List<String>> getMap(List<String> strings) {
    return strings.stream().collect(
      Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new))
    );
}

作为旁注,你可以有一个通用的方法:

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

此声明的优点是,如果调用方愿意,您现在可以使用它来将特定的 s 作为结果,或者 s 的特定结果:HashMapArrayListLinkedHashMapLinkedLists

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

但是,在这一点上,直接在代码中使用可能更简单...groupingBy


答案 2

如果您计划创建类似于 以下内容的地图,则可以使用此解决方案:Map<property_1, List<property_2>>

Map<String, List<String>> ds= requestList.stream().collect(
    Collectors.groupingBy(TagRequest::getProperty_1, HashMap::new, 
    Collectors.mapping(TagRequest::getProperty_2, Collectors.toList()))
);

如果计划创建类似于 的地图,可以使用:Map<property_1, Set<property_2>>

Map<String, List<String>> ds= requestList.stream().collect(
    Collectors.groupingBy(TagRequest::getProperty_1, HashMap::new, 
    Collectors.mapping(TagRequest::getProperty_2, Collectors.toSet()))
);

推荐