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.