将 CustomObject 列表转换为 Guava Table 集合,复杂度较低
Conversion of List of CustomObject to Guava Table collection with less complexity
我有
class CustomObject {
Integer day;
List<InnerObject> innerObjects;
///getter setter
}
class InnerObject {
String id;
List<String> someVal;
//getter setter
}
我有一个
List<CustomObject>
我想要
Table<String, Integer, List<String>>
我要table表示id (from InnerObject)
-> (day (from Custom object)
,List of someVal (from InnerObject)
为了让它更干净,我稍微调整了名称,但结构与预期的相同。
现在我的做法是
final List<CustomObject> objects = ???
final Map<Integer, List<InnerObject>> dayVsInnerObjects = objects.stream()
.collect(toMap(CustomObject::getDay, CustomObject::getInnerObjects));
final Table<String, Integer, List<String>> table = HashBasedTable.create();
dayVsInnerObjects.forEach((day, innerObjects) ->
innerObjects.forEach(i -> {
table.put(i.getId(), day, i.getSomeVal());
})
);
我的问题:
- 有更好的方法吗?可能是更好的 guava/Collection API 可以使它更干净一些。
- 现在 table 正在填充,它是 mutable。我们能不能有办法在创建它的时候让它变得免疫table。
- 如果这里可以降低时间复杂度。
如果我没有遗漏任何东西,你可以为此做一个自定义收集器(我真的不明白你为什么要先收集到 Map
):
.stream()
.collect((Collector.of(
HashBasedTable::create,
(table, co) -> {
for (InnerObject io : co.getInnerObjects()) {
table.put(io.getId(), co.getDay(), io.getSomeVal());
}
},
(left, right) -> {
left.putAll(right);
return left;
}));
EDIT 正如另一个答案已经显示的那样 - 已经有内置收集器,因为 version 21
.
您可以使用 flatMap
on the initial stream to get a stream of Map.Entry<Integer, InnerObject>
(the key being the day) and use these entries to collect directly to a Table
by means of Guava's Tables.toTable
内置收集器:
Table<String, Integer, List<String>> table = objects.stream()
.flatMap(custom -> custom.getInnerObjects().stream()
.map(inner -> new SimpleEntry<>(custom.getDay(), inner)))
.collect(Tables.toTable(
entry -> entry.getValue().getId(),
entry -> entry.getKey(),
entry -> entry.getValue().getSomeVal(),
HashBasedTable::create));
如果你想让Table
不可变,可以使用Guava的方法Tables.unmodifiableTable
:
Table<String, Integer, List<String>> unmodifiableTable = Tables.unmodifiableTable(table);
或者,如果你想在采集时得到不可修改的Table
:
Table<String, Integer, List<String>> unmodifiableTable = objects.stream()
.flatMap(custom -> custom.getInnerObjects().stream()
.map(inner -> new SimpleEntry<>(custom.getDay(), inner)))
.collect(Collectors.collectingAndThen(
Tables.toTable(
entry -> entry.getValue().getId(),
entry -> entry.getKey(),
entry -> entry.getValue().getSomeVal(),
HashBasedTable::create),
Tables::unmodifiableTable);
注意:我使用的是 Guava 22.0 版,但正如 Eugene 在 中所说,此功能从 21.0 版开始可用。
关于你的问题,我想我已经回答了1和2。关于3,不,没有办法降低时间复杂度,因为你需要在每个[=21中访问每个InnerObject
=].
我有
class CustomObject {
Integer day;
List<InnerObject> innerObjects;
///getter setter
}
class InnerObject {
String id;
List<String> someVal;
//getter setter
}
我有一个
List<CustomObject>
我想要
Table<String, Integer, List<String>>
我要table表示id (from InnerObject)
-> (day (from Custom object)
,List of someVal (from InnerObject)
为了让它更干净,我稍微调整了名称,但结构与预期的相同。
现在我的做法是
final List<CustomObject> objects = ???
final Map<Integer, List<InnerObject>> dayVsInnerObjects = objects.stream()
.collect(toMap(CustomObject::getDay, CustomObject::getInnerObjects));
final Table<String, Integer, List<String>> table = HashBasedTable.create();
dayVsInnerObjects.forEach((day, innerObjects) ->
innerObjects.forEach(i -> {
table.put(i.getId(), day, i.getSomeVal());
})
);
我的问题:
- 有更好的方法吗?可能是更好的 guava/Collection API 可以使它更干净一些。
- 现在 table 正在填充,它是 mutable。我们能不能有办法在创建它的时候让它变得免疫table。
- 如果这里可以降低时间复杂度。
如果我没有遗漏任何东西,你可以为此做一个自定义收集器(我真的不明白你为什么要先收集到 Map
):
.stream()
.collect((Collector.of(
HashBasedTable::create,
(table, co) -> {
for (InnerObject io : co.getInnerObjects()) {
table.put(io.getId(), co.getDay(), io.getSomeVal());
}
},
(left, right) -> {
left.putAll(right);
return left;
}));
EDIT 正如另一个答案已经显示的那样 - 已经有内置收集器,因为 version 21
.
您可以使用 flatMap
on the initial stream to get a stream of Map.Entry<Integer, InnerObject>
(the key being the day) and use these entries to collect directly to a Table
by means of Guava's Tables.toTable
内置收集器:
Table<String, Integer, List<String>> table = objects.stream()
.flatMap(custom -> custom.getInnerObjects().stream()
.map(inner -> new SimpleEntry<>(custom.getDay(), inner)))
.collect(Tables.toTable(
entry -> entry.getValue().getId(),
entry -> entry.getKey(),
entry -> entry.getValue().getSomeVal(),
HashBasedTable::create));
如果你想让Table
不可变,可以使用Guava的方法Tables.unmodifiableTable
:
Table<String, Integer, List<String>> unmodifiableTable = Tables.unmodifiableTable(table);
或者,如果你想在采集时得到不可修改的Table
:
Table<String, Integer, List<String>> unmodifiableTable = objects.stream()
.flatMap(custom -> custom.getInnerObjects().stream()
.map(inner -> new SimpleEntry<>(custom.getDay(), inner)))
.collect(Collectors.collectingAndThen(
Tables.toTable(
entry -> entry.getValue().getId(),
entry -> entry.getKey(),
entry -> entry.getValue().getSomeVal(),
HashBasedTable::create),
Tables::unmodifiableTable);
注意:我使用的是 Guava 22.0 版,但正如 Eugene 在
关于你的问题,我想我已经回答了1和2。关于3,不,没有办法降低时间复杂度,因为你需要在每个[=21中访问每个InnerObject
=].