如何用 Stream API 替换嵌套循环
How can I replace the nested loops with Stream API
是否可以将下面代码中的嵌套循环替换为 Stream API?
Map<String, List<Role>> roleByUserUsername = roles.stream()
.collect(Collectors.groupingBy(//some foo that return userName
Role::getRoleId,
Collectors.toList()));
List<User> users = List.of(new User(), new User());
HashMap<String, User> userByRoleId = new HashMap<>();
for (final User user : users) {
for (final Role roles1 : roleByUserUsername.get(user.getPassword())) {
userByRoleId.put(roles1.getRoleId(), user);
}
}
试试这个
users.stream().forEach(user->roleByUserUsername.get(user.getPassword()).forEach(role->userByRoleId.put(role.getRoleId(), user)));
您需要展平从地图roleByUsername
获得的角色列表。
顺便说一句,有一个不一致的地方:根据它的名字,map 意味着包含 usernames作为 keys,但在循环中,您通过提供调用 getPassword()
.
返回的结果来访问它
然后您需要应用 collect
作为终端操作并提供收集器 toMap()
作为参数以生成将 roleId
与单个 [=47= 相关联的映射]用户.
List<Role> roles = // initialing the list of roles
Map<String, List<Role>> roleByUsername = roles.stream()
.collect(Collectors.groupingBy(Role::getRoleId));
List<User> users = List.of(new User(), new User());
Map<String, User> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
但是这里有一个逻辑问题。假设 roleId
对于每个角色都是唯一的,但是可以有多个用户具有相同的角色。除非您设计了一个应用程序,其中每个 用户 都有一个唯一的 角色 。
因此,将映射类型更改为 Map<String, List<User>>
是有意义的,这样 user 的集合将映射到每个 roleId
。
为此,我们需要将收集器从 toMap
更改为 groupingBy()
以及 mapping()
和 toList()
。
Map<String, List<User>> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
旁注:
Collector groupingBy()
有一种风格,它只需要一个参数 - classifier
function。默认情况下,它会将映射到相同 key 的所有元素存储到列表中。您不需要提供 toList()
作为下游。
针对 Map
等接口编写代码,不要使其依赖于具体实现:What does it mean to "program to an interface"?
是否可以将下面代码中的嵌套循环替换为 Stream API?
Map<String, List<Role>> roleByUserUsername = roles.stream()
.collect(Collectors.groupingBy(//some foo that return userName
Role::getRoleId,
Collectors.toList()));
List<User> users = List.of(new User(), new User());
HashMap<String, User> userByRoleId = new HashMap<>();
for (final User user : users) {
for (final Role roles1 : roleByUserUsername.get(user.getPassword())) {
userByRoleId.put(roles1.getRoleId(), user);
}
}
试试这个
users.stream().forEach(user->roleByUserUsername.get(user.getPassword()).forEach(role->userByRoleId.put(role.getRoleId(), user)));
您需要展平从地图roleByUsername
获得的角色列表。
顺便说一句,有一个不一致的地方:根据它的名字,map 意味着包含 usernames作为 keys,但在循环中,您通过提供调用 getPassword()
.
然后您需要应用 collect
作为终端操作并提供收集器 toMap()
作为参数以生成将 roleId
与单个 [=47= 相关联的映射]用户.
List<Role> roles = // initialing the list of roles
Map<String, List<Role>> roleByUsername = roles.stream()
.collect(Collectors.groupingBy(Role::getRoleId));
List<User> users = List.of(new User(), new User());
Map<String, User> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
但是这里有一个逻辑问题。假设 roleId
对于每个角色都是唯一的,但是可以有多个用户具有相同的角色。除非您设计了一个应用程序,其中每个 用户 都有一个唯一的 角色 。
因此,将映射类型更改为 Map<String, List<User>>
是有意义的,这样 user 的集合将映射到每个 roleId
。
为此,我们需要将收集器从 toMap
更改为 groupingBy()
以及 mapping()
和 toList()
。
Map<String, List<User>> userByRoleId = users.stream()
.flatMap(user -> roleByUsername.get(user.getPassword()).stream()
.map(role -> Map.entry(role.getRoleId(), user)))
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
旁注:
Collector
groupingBy()
有一种风格,它只需要一个参数 -classifier
function。默认情况下,它会将映射到相同 key 的所有元素存储到列表中。您不需要提供toList()
作为下游。针对
Map
等接口编写代码,不要使其依赖于具体实现:What does it mean to "program to an interface"?