将 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());
            })
);

我的问题:

  1. 有更好的方法吗?可能是更好的 guava/Collection API 可以使它更干净一些。
  2. 现在 table 正在填充,它是 mutable。我们能不能有办法在创建它的时候让它变得免疫table。
  3. 如果这里可以降低时间复杂度。

如果我没有遗漏任何东西,你可以为此做一个自定义收集器(我真的不明白你为什么要先收集到 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 =].