为了提高效率,我经常遇到需要多地图地图的情况。我更愿意使用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
lambdas来映射每个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。但这个过程很快就变得令人目不暇接。
有一种有效的方法吗?
答案 0 :(得分:5)
您是否尝试过直截了当的方法?
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
);
}
答案 1 :(得分:2)
我也没有看到将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);
}