如何将 List<V> 转换为 Map<K, List<V>>,具有 Java 8 个流和自定义 List 和 Map 供应商?
How to convert List<V> into Map<K, List<V>>, with Java 8 streams and custom List and Map suppliers?
很容易将List<V>
转换成Map<K, List<V>>
。例如:
public Map<Integer, List<String>> getMap(List<String> strings) {
return
strings.stream()
.collect(Collectors.groupingBy(String::length));
}
但是我想和我自己的List
和Map
供应商.
一起做
我想到了这个:
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));
如果我只需要定义 List
供应商,而不是 Map
供应商呢?
你可以有以下内容:
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream().collect(
Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new))
);
}
收集器groupingBy(classifier, mapFactory, downstream)
can be used to specify which type of map is wanted, by passing it a supplier of the wanted map for the mapFactory
. Then, the downstream collector, which is used to collect elements grouped to the same key, is toCollection(collectionFactory)
,可以收集到从给定供应商处获得的集合。
这确保映射 returned 是 HashMap
并且每个值中的列表是 ArrayList
。请注意,如果您想要 return 映射和集合的特定实现,那么您很可能希望该方法也 return 这些特定类型,因此您可以使用它们的属性。
如果你只想指定一个集合供应商,并保持groupingBy
默认地图,你可以在上面的代码中省略供应商并使用two arguments overload:
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))
);
}
此声明的优势在于,您现在可以使用它来获得特定的 HashMap
of ArrayList
s 作为结果,或者 LinkedHashMap
of LinkedLists
s 作为结果,如果来电者希望:
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
可能会更简单...
我也遇到过类似的情况。我这样解决了:
Map<String, List<Object>> map = stringList.stream().collect(Collectors.toMap(str -> str, str -> populateList(str)));
而populateList()
是:
private List<Object> populateList(final String str) {
...
....
List<Object> list = // dao.get(str);
return list;
}
如果您打算创建类似于 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()))
);
很容易将List<V>
转换成Map<K, List<V>>
。例如:
public Map<Integer, List<String>> getMap(List<String> strings) {
return
strings.stream()
.collect(Collectors.groupingBy(String::length));
}
但是我想和我自己的List
和Map
供应商.
我想到了这个:
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));
如果我只需要定义 List
供应商,而不是 Map
供应商呢?
你可以有以下内容:
public Map<Integer, List<String>> getMap(List<String> strings) {
return strings.stream().collect(
Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new))
);
}
收集器groupingBy(classifier, mapFactory, downstream)
can be used to specify which type of map is wanted, by passing it a supplier of the wanted map for the mapFactory
. Then, the downstream collector, which is used to collect elements grouped to the same key, is toCollection(collectionFactory)
,可以收集到从给定供应商处获得的集合。
这确保映射 returned 是 HashMap
并且每个值中的列表是 ArrayList
。请注意,如果您想要 return 映射和集合的特定实现,那么您很可能希望该方法也 return 这些特定类型,因此您可以使用它们的属性。
如果你只想指定一个集合供应商,并保持groupingBy
默认地图,你可以在上面的代码中省略供应商并使用two arguments overload:
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))
);
}
此声明的优势在于,您现在可以使用它来获得特定的 HashMap
of ArrayList
s 作为结果,或者 LinkedHashMap
of LinkedLists
s 作为结果,如果来电者希望:
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
可能会更简单...
我也遇到过类似的情况。我这样解决了:
Map<String, List<Object>> map = stringList.stream().collect(Collectors.toMap(str -> str, str -> populateList(str)));
而populateList()
是:
private List<Object> populateList(final String str) {
...
....
List<Object> list = // dao.get(str);
return list;
}
如果您打算创建类似于 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()))
);