使用带 Java 8 的流从列表生成地图
Generate a Map from a list using Streams with Java 8
我有一个 列表 String
。
我想将每个 string 存储为 key 并将字符串的 length 存储为 value in a Map
(say HashMap
).
我做不到。
List<String> ls = Arrays.asList("James", "Sam", "Scot", "Elich");
Map<String,Integer> map = new HashMap<>();
Function<String, Map<String, Integer>> fs = new Function<>() {
@Override
public Map<String, Integer> apply(String s) {
map.put(s,s.length());
return map;
}
};
Map<String, Integer> nmap = ls
.stream()
.map(fs).
.collect(Collectors.toMap()); //Lost here
System.out.println(nmap);
所有字符串都是唯一的。
不需要像您创建的 函数 那样用自己的 map 包装每个字符串。
相反,您需要在调用 Collectors.toMap()
时提供适当的 参数 :
keyMapper
- 负责从流元素中提取 key 的函数。
valueMapper
- 从流元素生成 值 的函数。
因此,你需要流元素本身是一个 key 我们可以使用 Function.identity()
,它比 lambda str -> str
更具描述性,但是一模一样
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // extracting a key
String::length // extracting a value
));
如果源列表可能包含重复项,您需要提供第三个参数 - mergeFunction,它将负责解决重复项。
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // key
String::length, // value
(left, right) -> left // resolving duplicates
));
你说过不会有重复的字符串。但是,如果有人通过了,您可以使用 distinct()
(内部使用 set)来确保它不会引起问题。
a-> a
是使用流值的shorthand。本质上是一个 returns 其参数的 lambda。
distinct()
删除所有重复的字符串
Map<String, Integer> result = names.stream().distinct()
.collect(Collectors.toMap(a -> a, String::length));
如果你想得到一个String
的长度,你可以直接像someString.length()
那样做。但是假设您想要获取所有按特定长度键控的字符串的映射。您可以使用 Collectors.groupingBy()
来做到这一点,默认情况下会将重复项放入列表中。在这种情况下,副本将是字符串的长度。
- 使用字符串的
length
作为关键字。
- 该值将是一个
List<String>
来保存匹配该长度的所有字符串。
List<String> names = List.of("James", "Sam", "Scot",
"Elich", "lucy", "Jennifer","Bob", "Joe", "William");
Map<Integer, List<String>> lengthMap = names.stream()
.distinct()
.collect(Collectors.groupingBy(String::length));
lengthMap.entrySet().forEach(System.out::println);
打印
3=[Sam, Bob, Joe]
4=[Scot, lucy]
5=[James, Elich]
7=[William]
8=[Jennifer]
我有一个 列表 String
。
我想将每个 string 存储为 key 并将字符串的 length 存储为 value in a Map
(say HashMap
).
我做不到。
List<String> ls = Arrays.asList("James", "Sam", "Scot", "Elich");
Map<String,Integer> map = new HashMap<>();
Function<String, Map<String, Integer>> fs = new Function<>() {
@Override
public Map<String, Integer> apply(String s) {
map.put(s,s.length());
return map;
}
};
Map<String, Integer> nmap = ls
.stream()
.map(fs).
.collect(Collectors.toMap()); //Lost here
System.out.println(nmap);
所有字符串都是唯一的。
不需要像您创建的 函数 那样用自己的 map 包装每个字符串。
相反,您需要在调用 Collectors.toMap()
时提供适当的 参数 :
keyMapper
- 负责从流元素中提取 key 的函数。valueMapper
- 从流元素生成 值 的函数。
因此,你需要流元素本身是一个 key 我们可以使用 Function.identity()
,它比 lambda str -> str
更具描述性,但是一模一样
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // extracting a key
String::length // extracting a value
));
如果源列表可能包含重复项,您需要提供第三个参数 - mergeFunction,它将负责解决重复项。
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // key
String::length, // value
(left, right) -> left // resolving duplicates
));
你说过不会有重复的字符串。但是,如果有人通过了,您可以使用 distinct()
(内部使用 set)来确保它不会引起问题。
a-> a
是使用流值的shorthand。本质上是一个 returns 其参数的 lambda。distinct()
删除所有重复的字符串
Map<String, Integer> result = names.stream().distinct()
.collect(Collectors.toMap(a -> a, String::length));
如果你想得到一个String
的长度,你可以直接像someString.length()
那样做。但是假设您想要获取所有按特定长度键控的字符串的映射。您可以使用 Collectors.groupingBy()
来做到这一点,默认情况下会将重复项放入列表中。在这种情况下,副本将是字符串的长度。
- 使用字符串的
length
作为关键字。 - 该值将是一个
List<String>
来保存匹配该长度的所有字符串。
List<String> names = List.of("James", "Sam", "Scot",
"Elich", "lucy", "Jennifer","Bob", "Joe", "William");
Map<Integer, List<String>> lengthMap = names.stream()
.distinct()
.collect(Collectors.groupingBy(String::length));
lengthMap.entrySet().forEach(System.out::println);
打印
3=[Sam, Bob, Joe]
4=[Scot, lucy]
5=[James, Elich]
7=[William]
8=[Jennifer]