创建一个 ImmutableMap<P,ImmutableMultimap<C,V>> 流收集器
Creating an ImmutableMap<P,ImmutableMultimap<C,V>> stream Collector
我经常 运行 遇到这样的情况:为了提高效率,我需要一张包含多个地图的地图。我更喜欢使用 Guava 的 ImmutableMap
和 ImmutableMultimap
来完成这个。
我已经为 Guava 借用并创建了几个 Collector
实现,因此我可以利用 Java 8 个流。例如,这是 ImmutableListMultimap
的收集器。
public static <T, K, V> Collector<T, ?, ImmutableListMultimap<K, V>> toImmutableListMultimap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
Supplier<ImmutableListMultimap.Builder<K, V>> supplier = ImmutableListMultimap.Builder::new;
BiConsumer<ImmutableListMultimap.Builder<K, V>, T> accumulator = (b, t) -> b
.put(keyMapper.apply(t), valueMapper.apply(t));
BinaryOperator<ImmutableListMultimap.Builder<K, V>> combiner = (l, r) -> l.putAll(r.build());
Function<ImmutableListMultimap.Builder<K, V>, ImmutableListMultimap<K, V>> finisher = ImmutableListMultimap.Builder::build;
return Collector.of(supplier, accumulator, combiner, finisher);
}
我想为我当前的问题创建一个非常相似的收集器。我希望我的收集器创建一个 ImmutableMap<P,ImmutableMultimap<C,V>>
,其中 P
是主地图的父键,C
是子地图的子键。将提供两个 Function
lambda 来为每个 T
项映射这些键。
说起来容易做起来难。到目前为止,我所做的所有工作都是创建方法存根。
public static <T, P, C, V> Collector<T, ?, ImmutableMap<P, ImmutableMultimap<C,V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
}
因为 Guava 不可变集合构建器不允许查找,我发现自己使用可变哈希映射来查找以前捕获的值,所以我只会在 P 键不存在时创建一个新的 ImmutableMultimap。但是这个过程很快就变得头晕目眩。
有没有有效的方法来做到这一点?
我也没有看到将 Guava 构建器用于外部地图的方法。然而,涉及可变哈希图并没有那么令人眼花缭乱,不是吗?
使用 ImmutableMap.Builder 和您的 toImmutableListMultimap,可以轻松获得 ImmutableMap-Collector。
这可以在内部多图的整理器中使用,产生以下代码:
public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
final Supplier<ImmutableMap.Builder<K, V>> supplier = ImmutableMap.Builder::new;
final BiConsumer<ImmutableMap.Builder<K, V>, T> accumulator = (b, t) -> b
.put(keyMapper.apply(t), valueMapper.apply(t));
final BinaryOperator<ImmutableMap.Builder<K, V>> combiner = (l, r) -> l
.putAll(r.build());
final Function<ImmutableMap.Builder<K, V>, ImmutableMap<K, V>> finisher = ImmutableMap.Builder::build;
return Collector.of(supplier, accumulator, combiner, finisher);
}
public static <T, P, C, V> Collector<T, Map<P, ImmutableListMultimap.Builder<C, V>>, ImmutableMap<P, ImmutableMultimap<C, V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
final Supplier<Map<P, ImmutableListMultimap.Builder<C, V>>> supplier = HashMap::new;
final BiConsumer<Map<P, ImmutableListMultimap.Builder<C, V>>, T> accumulator = (
map, element) -> map.computeIfAbsent(
parentKeyMapper.apply(element),
x -> ImmutableListMultimap.builder()).put(
childKeyMapper.apply(element), valueMapper.apply(element));
final BinaryOperator<Map<P, ImmutableListMultimap.Builder<C, V>>> combiner = (
l, r) -> {
l.putAll(r);
return l;
};
final Function<Map<P, ImmutableListMultimap.Builder<C, V>>, ImmutableMap<P, ImmutableMultimap<C, V>>> finisher = map -> map
.entrySet()
.stream()
.collect(
toImmutableMap(Map.Entry::getKey, e -> e.getValue()
.build()));
return Collector.of(supplier, accumulator, combiner, finisher);
}
您尝试过直接的方法吗?
collectingAndThen(
groupingBy(
parentKeyMapper,
toImmutableListMultimap(childKeyMapper, valueMapper)
),
ImmutableMap::copyOf
);
更新: 上面的代码在 JDK 下运行良好,但 Eclipse 编译器对此有抱怨。这是 Eclipse 将接受的版本:
public static <T, P, C, V> Collector<T, ?, ImmutableMap<P, ImmutableMultimap<C, V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
return Collectors.collectingAndThen(
Collectors.groupingBy(
parentKeyMapper,
SO29417692.<T,C,V>toImmutableListMultimap(childKeyMapper, valueMapper)
),
ImmutableMap::<P,ImmutableMultimap<C,V>>copyOf
);
}
我经常 运行 遇到这样的情况:为了提高效率,我需要一张包含多个地图的地图。我更喜欢使用 Guava 的 ImmutableMap
和 ImmutableMultimap
来完成这个。
我已经为 Guava 借用并创建了几个 Collector
实现,因此我可以利用 Java 8 个流。例如,这是 ImmutableListMultimap
的收集器。
public static <T, K, V> Collector<T, ?, ImmutableListMultimap<K, V>> toImmutableListMultimap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
Supplier<ImmutableListMultimap.Builder<K, V>> supplier = ImmutableListMultimap.Builder::new;
BiConsumer<ImmutableListMultimap.Builder<K, V>, T> accumulator = (b, t) -> b
.put(keyMapper.apply(t), valueMapper.apply(t));
BinaryOperator<ImmutableListMultimap.Builder<K, V>> combiner = (l, r) -> l.putAll(r.build());
Function<ImmutableListMultimap.Builder<K, V>, ImmutableListMultimap<K, V>> finisher = ImmutableListMultimap.Builder::build;
return Collector.of(supplier, accumulator, combiner, finisher);
}
我想为我当前的问题创建一个非常相似的收集器。我希望我的收集器创建一个 ImmutableMap<P,ImmutableMultimap<C,V>>
,其中 P
是主地图的父键,C
是子地图的子键。将提供两个 Function
lambda 来为每个 T
项映射这些键。
说起来容易做起来难。到目前为止,我所做的所有工作都是创建方法存根。
public static <T, P, C, V> Collector<T, ?, ImmutableMap<P, ImmutableMultimap<C,V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
}
因为 Guava 不可变集合构建器不允许查找,我发现自己使用可变哈希映射来查找以前捕获的值,所以我只会在 P 键不存在时创建一个新的 ImmutableMultimap。但是这个过程很快就变得头晕目眩。
有没有有效的方法来做到这一点?
我也没有看到将 Guava 构建器用于外部地图的方法。然而,涉及可变哈希图并没有那么令人眼花缭乱,不是吗? 使用 ImmutableMap.Builder 和您的 toImmutableListMultimap,可以轻松获得 ImmutableMap-Collector。 这可以在内部多图的整理器中使用,产生以下代码:
public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
final Supplier<ImmutableMap.Builder<K, V>> supplier = ImmutableMap.Builder::new;
final BiConsumer<ImmutableMap.Builder<K, V>, T> accumulator = (b, t) -> b
.put(keyMapper.apply(t), valueMapper.apply(t));
final BinaryOperator<ImmutableMap.Builder<K, V>> combiner = (l, r) -> l
.putAll(r.build());
final Function<ImmutableMap.Builder<K, V>, ImmutableMap<K, V>> finisher = ImmutableMap.Builder::build;
return Collector.of(supplier, accumulator, combiner, finisher);
}
public static <T, P, C, V> Collector<T, Map<P, ImmutableListMultimap.Builder<C, V>>, ImmutableMap<P, ImmutableMultimap<C, V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
final Supplier<Map<P, ImmutableListMultimap.Builder<C, V>>> supplier = HashMap::new;
final BiConsumer<Map<P, ImmutableListMultimap.Builder<C, V>>, T> accumulator = (
map, element) -> map.computeIfAbsent(
parentKeyMapper.apply(element),
x -> ImmutableListMultimap.builder()).put(
childKeyMapper.apply(element), valueMapper.apply(element));
final BinaryOperator<Map<P, ImmutableListMultimap.Builder<C, V>>> combiner = (
l, r) -> {
l.putAll(r);
return l;
};
final Function<Map<P, ImmutableListMultimap.Builder<C, V>>, ImmutableMap<P, ImmutableMultimap<C, V>>> finisher = map -> map
.entrySet()
.stream()
.collect(
toImmutableMap(Map.Entry::getKey, e -> e.getValue()
.build()));
return Collector.of(supplier, accumulator, combiner, finisher);
}
您尝试过直接的方法吗?
collectingAndThen(
groupingBy(
parentKeyMapper,
toImmutableListMultimap(childKeyMapper, valueMapper)
),
ImmutableMap::copyOf
);
更新: 上面的代码在 JDK 下运行良好,但 Eclipse 编译器对此有抱怨。这是 Eclipse 将接受的版本:
public static <T, P, C, V> Collector<T, ?, ImmutableMap<P, ImmutableMultimap<C, V>>> toPartitionedImmutableMultimap(
Function<? super T, ? extends P> parentKeyMapper,
Function<? super T, ? extends C> childKeyMapper,
Function<? super T, ? extends V> valueMapper) {
return Collectors.collectingAndThen(
Collectors.groupingBy(
parentKeyMapper,
SO29417692.<T,C,V>toImmutableListMultimap(childKeyMapper, valueMapper)
),
ImmutableMap::<P,ImmutableMultimap<C,V>>copyOf
);
}