给定一个 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();
}