java - 将一个集合划分为具有相等字段的对象的子集?
问题描述
我目前正在尝试在 java 中实现数据结构,并希望将一组输入对象划分为具有相同字段的不同对象子集。
An example use case
:
我们希望将人员列表划分为特定日期出生的人员的子列表。
Input
:person1 1990 年出生,person2 2000 年出生,person3 1990 年出生。
Output
:
1 -> 人 1,人 3
2 -> 人2
public Map<Integer, List<Foo>> getIntToFooMap(List<Foo> foos) {
Map<Integer, List<Foo>> map = new TreeMap<>(); // need keys to be automatically ordered.
List<Foo> foosWithSameSetId = new ArrayList<>();
if (!foos.isEmpty) {
for (Foo foo: foos) {
for (Foo foo2: foos) {
if (foo.getSetId().equals(foo2.getSetId())) {
foosWithSameSetId.add(foo2);
}
}
map.put(foo.getSetId(), foosWithSameSetId);
foosWithSameSetId.clear();
}
}
return map;
}
上面的代码不是最优的,时间复杂度是二次的,也不是线程安全的。有人能告诉我一个更好的方法将 List 或 Set 划分为具有相等字段的对象子集,在这种情况下是setId
.
解决方案
首先,不需要嵌套循环。您只需获取或创建当前foo
's的集合setId
,并将其添加foo
到其中:
for (Foo foo : foos) {
map.computeIfAbsent(foo.getSetId(), i -> new ArrayList<>()).add(foo);
}
这相当于:
for (Foo foo : foos) {
List<Foo> list = map.get(foo.getSetId());
if(null == list) list = new ArrayList<>();
list.add(foo);
}
现在,您需要记住地图实现的时间复杂度。
作为替代方案,groupingBy
流收集器会为您的代码添加简洁性:
return foos.stream().collect(
Collectors.groupingBy(Foo::getSetId, TreeMap::new, Collectors.toList()));
推荐阅读
- bigbluebutton - 使用外部 Freeswitch 配置 BigBlueButton
- javascript - 如何在功能组件中将一种状态与另一种状态相等
- monitoring - 如何在 grafana 中显示服务器下拉列表
- angular - 从服务器获取数据并将其添加到局部变量以供将来在 json 中使用
- javascript - 类型错误:button.classList 未定义
- node.js - GET http://localhost:3000/ 404(未找到),实际上是在调用 POST 但得到 GET
- sql-server - 如何将 SQL Server 数据库放在 DVD 上
- javascript - Fetch API 无法加载 URL 方案对于 CORS 请求必须是“http”或“https”
- java - 运行 Jar 时出现 NoClassDefFoundError
- image-processing - 根据图片从数据库中查找相似图片