创建ImmutableMap <p,immutablemultimap <c,v>&gt; stream Collector </p,immutablemultimap <c,v>

时间:2015-04-02 16:18:58

标签: java lambda java-8 guava java-stream

为了提高效率,我经常遇到需要多地图地图的情况。我更愿意使用Guava的ImmutableMapImmutableMultimap来实现这一目标。

我已经为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。但这个过程很快就变得令人目不暇接。

有一种有效的方法吗?

2 个答案:

答案 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);
}