I have
class CustomObject {
Integer day;
List<InnerObject> innerObjects;
///getter setter
}
class InnerObject {
String id;
List<String> someVal;
//getter setter
}
I have a
List<CustomObject>
and I want
Table<String, Integer, List<String>>
I want table to represent id (from InnerObject)
-> (day (from Custom object)
, List of someVal (from InnerObject)
Just to make it clean I tweaked names a bit but structure is same as what is expected.
Now how I am doing is
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());
})
);
My questions:
You could use 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
built-in collector:
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));
If you want the Table
to be immutable, you can use Guava's method Tables.unmodifiableTable
:
Table<String, Integer, List<String>> unmodifiableTable = Tables.unmodifiableTable(table);
Or, if you want to get the unmodifiable Table
when collecting:
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);
Note: I'm using Guava version 22.0, but as Eugene says in his comment below, this functionality is available since version 21.0.
As for your questions, I think I've already answered 1 and 2. Regarding 3, no, there's no way to reduce time complexity, as you need to access each InnerObject
within each CustomObject
.
If I am not missing anything you can do a custom collector for that (I don't really understand why you are collecting first to a 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 as the other answer is already showing - there are build-in collectors for that already, since version 21
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With