给定一个 Map<K, List<V>> 类型的映射,如何使用 Java 流更新 List<V> 中的值?
Given a map of type Map<K, List<V>>, how to update value within List<V> using Java streams?
我收到了一些 API 的回复,其类型为:
public class Response {
private String role;
private String permission;
// Setters and getters
}
Role
的值可能类似于 "Admin"
、"User"
等,权限值可能类似于 "R-4"
、"C-44"
等 "R-"
表示地区,"C-"
表示国家。
所以最初我构造 Map 通过做:
Map<String, Set<String>> initialMap= responseList.stream().collect(
Collectors.groupingBy(Reponse::getRole, HashMap::new,
Collectors.mapping(Reponse::getPermission, Collectors.toSet()))
);
但对于我的应用程序,我希望地图为 Map<String, Set<Long>>
,它指示角色以及与该角色关联的各个国家/地区。基本上,我想从值为 hashmap
的集合中删除 "R-"
和 "C-"
。当值类似于 "R-4"
时,我想删除 "R-"
并使用在此示例中为 4
的 id,并将此 id 传递给数据库以获取 List<Long> countries
并添加它转化为 hashmap
的价值。当值类似于 "C-44"
时,我想删除 "C-"
并将该 id 添加到 hashmap
的值中。
一种方法是手动遍历 initialMap
的每个条目,然后获取相应的 Set<String>
值,然后再次遍历 Set<String>
以获取 String
值,然后将其转换为 Long
。我在想有没有更好的方法可以使用 Streams 来做到这一点?我可以直接从我最初的 reponseList
构造 Map<String, Set<Long>>
吗?
你可以试试这个
Map<String, Set<String>> initialMap= responseList.stream().collect(
Collectors.groupingBy(Response::getRole, HashMap::new,
Collectors.mapping((Response res) -> Long.parseLong(res.getModifiedPermission()), Collectors.toSet()))
);
其中 getModifiedPermission()
是一个从权限中删除前缀的函数。
似乎这里的主要问题不是解析 region/country 的 ID,而是合并 List<Long>
包含多个国家 ID per regionId来自一些 DB/repository,以及来自权限 C-###
.
的单个国家/地区 ID
这可以使用 Java 9+ 中可用的 Collectors.flatMapping
来解决。此外,需要实现一个单独的函数 streamOfCountryIDs
以将响应的权限映射到此收集器的 Stream<Long>
:
Map<String, Set<Long>> converted = responses.stream()
.collect(Collectors.groupingBy(
Response::getRole,
Collectors.flatMapping(MyClass::streamOfCountryIDs, Collectors.toSet())
));
System.out.println(converted);
// MyClass
private static Stream<Long> streamOfCountryIDs(Response response) {
String permission = response.getPermission().toUpperCase();
if (permission.startsWith("R-")) {
return countryRepo.getCountriesByRegion(Long.parseLong(permission.substring(2)))
.stream();
} else if (permission.startsWith("C-")) {
return Stream.of(Long.parseLong(permission.substring(2)));
}
// log bad permission and return empty stream or throw an exception if needed
System.out.println("Bad permission: '" + permission + "'");
return Stream.empty();
}
我收到了一些 API 的回复,其类型为:
public class Response {
private String role;
private String permission;
// Setters and getters
}
Role
的值可能类似于 "Admin"
、"User"
等,权限值可能类似于 "R-4"
、"C-44"
等 "R-"
表示地区,"C-"
表示国家。
所以最初我构造 Map
Map<String, Set<String>> initialMap= responseList.stream().collect(
Collectors.groupingBy(Reponse::getRole, HashMap::new,
Collectors.mapping(Reponse::getPermission, Collectors.toSet()))
);
但对于我的应用程序,我希望地图为 Map<String, Set<Long>>
,它指示角色以及与该角色关联的各个国家/地区。基本上,我想从值为 hashmap
的集合中删除 "R-"
和 "C-"
。当值类似于 "R-4"
时,我想删除 "R-"
并使用在此示例中为 4
的 id,并将此 id 传递给数据库以获取 List<Long> countries
并添加它转化为 hashmap
的价值。当值类似于 "C-44"
时,我想删除 "C-"
并将该 id 添加到 hashmap
的值中。
一种方法是手动遍历 initialMap
的每个条目,然后获取相应的 Set<String>
值,然后再次遍历 Set<String>
以获取 String
值,然后将其转换为 Long
。我在想有没有更好的方法可以使用 Streams 来做到这一点?我可以直接从我最初的 reponseList
构造 Map<String, Set<Long>>
吗?
你可以试试这个
Map<String, Set<String>> initialMap= responseList.stream().collect(
Collectors.groupingBy(Response::getRole, HashMap::new,
Collectors.mapping((Response res) -> Long.parseLong(res.getModifiedPermission()), Collectors.toSet()))
);
其中 getModifiedPermission()
是一个从权限中删除前缀的函数。
似乎这里的主要问题不是解析 region/country 的 ID,而是合并 List<Long>
包含多个国家 ID per regionId来自一些 DB/repository,以及来自权限 C-###
.
这可以使用 Java 9+ 中可用的 Collectors.flatMapping
来解决。此外,需要实现一个单独的函数 streamOfCountryIDs
以将响应的权限映射到此收集器的 Stream<Long>
:
Map<String, Set<Long>> converted = responses.stream()
.collect(Collectors.groupingBy(
Response::getRole,
Collectors.flatMapping(MyClass::streamOfCountryIDs, Collectors.toSet())
));
System.out.println(converted);
// MyClass
private static Stream<Long> streamOfCountryIDs(Response response) {
String permission = response.getPermission().toUpperCase();
if (permission.startsWith("R-")) {
return countryRepo.getCountriesByRegion(Long.parseLong(permission.substring(2)))
.stream();
} else if (permission.startsWith("C-")) {
return Stream.of(Long.parseLong(permission.substring(2)));
}
// log bad permission and return empty stream or throw an exception if needed
System.out.println("Bad permission: '" + permission + "'");
return Stream.empty();
}