要反转此 Map,您需要遍历其条目,并为每个不同的用户创建一个条目,其中包含项目列表作为结果 Map 中的值。
Java 8 计算IfAbsent()
这个逻辑可以使用 Java 8 方法 Map.computeIfAbsent() 和 Map.forEach() 来实现。
Map<String, List<User>> usersByProject = // initilizing the source map
Map<User, List<String>> projectsByUser = new HashMap<>();
usersByProject.forEach((project, users) ->
users.forEach(user -> projectsByUser.computeIfAbsent(user, k -> new ArrayList<>())
.add(project))
);
流 API
基于流的实现需要更多的努力。
核心逻辑保持不变。但是有一个重要的特性:我们需要从源 Map 的每个条目中生成一系列新元素,包含对特定用户和项目的引用。
为了承载这些数据,我们需要一个辅助类型,Java 16 record 非常适合这个角色。快速而肮脏的替代方法是使用Map.Entry,但最好避免使用此选项,因为方法getKey()/getValue() 是匿名的,并且需要更多的努力来推理代码。如果您使用的是早期版本的 JDK,您还可以定义一个常规的 class。
public record UserProject(User user, String project) {}
这就是基于流的解决方案的样子:
Map<String, List<User>> usersByProject = Map.of(
"projectA", List.of(new User(1, "Bob"), new User(2, "John"), new User(3, "Mo")),
"projectB", List.of(new User(2, "John"), new User(3, "Mo")),
"projectC", List.of(new User(3, "Mo"))
);
Map<User, List<String>> projectByUsers = usersByProject.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().
map(user -> new UserProject(user, entry.getKey()))
)
.collect(Collectors.groupingBy(
UserProject::user,
Collectors.mapping(UserProject::project,
Collectors.toList())
));
projectsByUser.forEach((k, v) -> System.out.println(k + " -> " + v));
输出:
User[id=1, name=Bob] -> [projectA]
User[id=2, name=John] -> [projectA, projectB]
User[id=3, name=Mo] -> [projectA, projectC, projectB]