简体   繁体   中英

Given a map of type Map<K, List<V>>, how to update value within List<V> using Java streams?

I am receiving the resposne from some API which is of type:

public class Response {

    private String role;
    private String permission;
  
    // Setters and getters
}

value of Role could be something like "Admin" , "User" etc and value of permission is something like "R-4" , "C-44" etc. "R-" indicates Region and "C-" indicates country. So initially I constructed Map<String, Set> by doing:

Map<String, Set<String>> initialMap= responseList.stream().collect(
    Collectors.groupingBy(Reponse::getRole, HashMap::new, 
    Collectors.mapping(Reponse::getPermission, Collectors.toSet()))
);

But for my application, I want map to be Map<String, Set<Long>> which indicate Role and respective countries associated with that role. Basically, I want to remove "R-" and "C-" from the Set which is value of hashmap . When value is something like "R-4" then I want to remove "R-" and use id which is 4 in this example and pass this id to database to get the List<Long> countries and add it into value of hashmap . When value is something like "C-44" then I want to remove "C-" and add that id into value of hashmap . One approach could be manually iterating over each entry of initialMap and then getting it's corresponding Set<String> value and then again iterating over Set<String> to get String value and then converting it to Long . I was thinking is there any better way to do this using Streams? can I directly construct Map<String, Set<Long>> from my initial reponseList ?

You can try this

Map<String, Set<String>> initialMap= responseList.stream().collect(
    Collectors.groupingBy(Response::getRole, HashMap::new, 
    Collectors.mapping((Response res) -> Long.parseLong(res.getModifiedPermission()), Collectors.toSet()))
);

with getModifiedPermission() being a function which removes the prefix from Permission.

You can add a static method to Response class:

private static long toLong(Response response) {
    String[] arr = response.getPermission().split("-");
    String str = arr.length == 1 ? arr[0] : arr[1];
    return Long.parseLong(str);
}

Then you can create a method to convert the List to Map :

public static Map<String, Set<Long>> toMap(List<Response> response) {
    return response.stream().collect(Collectors.groupingBy(Response::getRole, 
                Collectors.mapping(Response::toLong, Collectors.toSet())));
}

Example:

List<Response> responseList = List.of(
        new Response("AAA","R-4"), 
        new Response("BBB","C-44"),
        new Response("CCC","444"));

Map<String, Set<Long>> map = toMap(responseList);

System.out.println(map);

Output:

{AAA=[4], BBB=[44], CCC=[444]}

It seems that the main issue here is not with parsing the id of region/country but rather with combining List<Long> containing multiple country IDs per regionId retrieved from some DB/repository, and a single country ID from the permission C-### .

This may be resolved using Collectors.flatMapping available in Java 9+. Also, a separate function streamOfCountryIDs needs to be implemented to map the response's permission into a Stream<Long> for this collector:

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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM