Java按值对map进行分组,其中value是List



我有一个

Map<String,List<User>>map = new HashMap<>();
map.put("projectA",Arrays.asList(new User(1,"Bob"),new User(2,"John"),new User(3,"Mo")));
map.put("projectB",Arrays.asList(new User(2,"John"),new User(3,"Mo")));
map.put("projectC",Arrays.asList(new User(3,"Mo")));

可以用String代替User。

字符串是一个项目名称,但是相同的用户可以关联到不同的项目。

我想得到像Map<User, List<String>>这样的东西,其中键将表示一个不同的用户和一个值,作为与他/她相关的项目名称的列表。

Bob  = [projectA]
John = [projectA, projectB]
Mo   = [projectA, projectB, projectC]

对于任何建议都要提前TQ。

循环遍历map的条目和其中的List:

public static void main(String[] args) {
Map<String, List<User>> map = new HashMap<>();
map.put("projectA", Arrays.asList(new User(1,"Bob"),new User(2,"John"),new User(3,"Mo")));
map.put("projectB",Arrays.asList(new User(2,"John"),new User(3,"Mo")));
map.put("projectC",Arrays.asList(new User(3,"Mo")));
Map<User, List<String>> result = new HashMap<>();
for(Map.Entry<String, List<User>> e:map.entrySet()) {
for(User u:e.getValue()) {
result.putIfAbsent(u, new ArrayList<>());
result.get(u).add(e.getKey());
}
}
System.out.println(result);
}
public static record User(int id, String name) {}

打印

{User[id=1, name=Bob]=[projectA], User[id=2, name=John]=[projectB, projectA], User[id=3, name=Mo]=[projectB, projectA, projectC]}

要反转这个Map,您需要遍历它的条目,并为每个不同的用户创建一个包含项目列表的条目,作为结果Map中的值。

Java 8 computeIfAbsent()

这个逻辑可以用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 h1> 于流的实现需要更多的努力。

核心逻辑保持不变。但是有一个重要的特性:我们需要从源Map的每个条目生成一个新元素序列,其中包含对特定用户和项目的引用。

为了携带这些数据,我们需要一个辅助类型,Java 16记录非常适合这个角色。另一种快速而肮脏的方法是使用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]

最新更新