Collectors.reducing 列出
Collectors.reducing to List
考虑这个 class:
@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
String name;
String languages;
}
我有一个 List<User>
,我想减少语言。输入:
List<User> list = new ArrayList<>();
list.add(new User("sam", "java"));
list.add(new User("sam", "js"));
list.add(new User("apollo", "html"));
预期输出:
[User(name=apollo, languages=html), User(name=sam, languages=java, js)]
我可以使用以下代码实现此目的:
List<User> l = list.stream()
.collect(Collectors.groupingBy(
u -> u.name,
Collectors.reducing((u1, u2) ->
new User(u1.name, u1.languages + ", " + u2.languages))))
.values()
.stream()
.filter(user -> user.get() != null)
.map(user -> user.get())
.collect(Collectors.toList());
System.out.println(l);
但是我不想创建两个流,可以使用单个流来实现吗?
您可以使用 Collectors.toMap()
:
List<User> l = new ArrayList<> (list.stream()
.collect(Collectors.toMap(u -> u.name,
u -> new User (u.name,u.languages),
(u1, u2) -> new User(u1.name, u1.languages + ", " + u2.languages)))
.values());
But I don't want to create two stream, can this be achieved using a single stream?
当然有可能,您有两个选择,在这两个选项中您都必须使用 Collect.collectingAndThen
从创建的 Map
.
中提取正确的值类型
您需要先使用以下lambda表达式:
BinaryOperator<User> binaryOperator = (u1, u2) ->
new User(u1.getName(), String.join(", ", u1.getLanguages(), u2.getLanguages()));
解决方案:
Collectors.toMap
Collectors.collectingAndThen
从 Map<String, User>
:
中提取值
List<User> l = list.stream() // Stream<User>
.collect(Collectors.collectingAndThen(
Collectors.toMap( // Map
User::getName, // ..name as key
user -> new User(user.getName(), user.getLanguages()), // ..value as user
binaryOperator), // ..combined
map -> new ArrayList<>(map.values()))); // extracted value
Collectors.groupingBy
和 Collectors.collectingAndThen
从 Map<String, Optional<User>>
中提取值,原因是 Collectors.reducing
:
List<User> ll = list.stream() // Stream<User>
.collect(Collectors.collectingAndThen(
Collectors.groupingBy( // Map<String, Optional<User>>
User::getName, // ... name as key
Collectors.reducing(binaryOperator)), // ... reduced value
map -> map.values().stream() // extracted value
.filter(Optional::isPresent) // ... where is Optional present
.map(Optional::get) // ... get it
.collect(Collectors.toList()))); // ... create a List<User>
请注意,我想您使用的是 java-8, there might be a different solution using java-11 或更高版本。
考虑这个 class:
@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
String name;
String languages;
}
我有一个 List<User>
,我想减少语言。输入:
List<User> list = new ArrayList<>();
list.add(new User("sam", "java"));
list.add(new User("sam", "js"));
list.add(new User("apollo", "html"));
预期输出:
[User(name=apollo, languages=html), User(name=sam, languages=java, js)]
我可以使用以下代码实现此目的:
List<User> l = list.stream()
.collect(Collectors.groupingBy(
u -> u.name,
Collectors.reducing((u1, u2) ->
new User(u1.name, u1.languages + ", " + u2.languages))))
.values()
.stream()
.filter(user -> user.get() != null)
.map(user -> user.get())
.collect(Collectors.toList());
System.out.println(l);
但是我不想创建两个流,可以使用单个流来实现吗?
您可以使用 Collectors.toMap()
:
List<User> l = new ArrayList<> (list.stream()
.collect(Collectors.toMap(u -> u.name,
u -> new User (u.name,u.languages),
(u1, u2) -> new User(u1.name, u1.languages + ", " + u2.languages)))
.values());
But I don't want to create two stream, can this be achieved using a single stream?
当然有可能,您有两个选择,在这两个选项中您都必须使用 Collect.collectingAndThen
从创建的 Map
.
您需要先使用以下lambda表达式:
BinaryOperator<User> binaryOperator = (u1, u2) ->
new User(u1.getName(), String.join(", ", u1.getLanguages(), u2.getLanguages()));
解决方案:
中提取值Collectors.toMap
Collectors.collectingAndThen
从Map<String, User>
:List<User> l = list.stream() // Stream<User> .collect(Collectors.collectingAndThen( Collectors.toMap( // Map User::getName, // ..name as key user -> new User(user.getName(), user.getLanguages()), // ..value as user binaryOperator), // ..combined map -> new ArrayList<>(map.values()))); // extracted value
Collectors.groupingBy
和Collectors.collectingAndThen
从Map<String, Optional<User>>
中提取值,原因是Collectors.reducing
:List<User> ll = list.stream() // Stream<User> .collect(Collectors.collectingAndThen( Collectors.groupingBy( // Map<String, Optional<User>> User::getName, // ... name as key Collectors.reducing(binaryOperator)), // ... reduced value map -> map.values().stream() // extracted value .filter(Optional::isPresent) // ... where is Optional present .map(Optional::get) // ... get it .collect(Collectors.toList()))); // ... create a List<User>
请注意,我想您使用的是 java-8, there might be a different solution using java-11 或更高版本。