【问题标题】:Creating an ImmutableMap<P,ImmutableMultimap<C,V>> stream Collector创建一个 ImmutableMap<P,ImmutableMultimap<C,V>> 流收集器
【发布时间】:2015-04-02 16:18:58
【问题描述】:

为了提高效率,我经常遇到需要多地图地图的情况。我更喜欢使用 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&lt;P,ImmutableMultimap&lt;C,V&gt;&gt;,其中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。但这个过程很快就变得令人眼花缭乱。

有没有有效的方法来做到这一点?

【问题讨论】:

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


    【解决方案1】:

    您是否尝试过直截了当的方法?

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

    【讨论】:

    • 我喜欢这个答案,并希望它起作用。我正在尝试找出泛型的编译错误...
    • @ThomasN。这与 java 1.8.0_25 编译得很好。您是否可能使用 eclipse 编译器?
    • 你怎么知道的?哈哈。为什么Eclipse有问题?除了它是一个有问题的 IDE 之外?
    • Eclipse 编译器存在类型推断问题。我不使用它,所以我不太了解它的问题。我摆弄了类型提示,直到 eclipse 停止抱怨。我会更新答案。
    • 我们使用这个收集器对几十万个对象进行了一些测试,这些对象具有驱动哈希码/等于的十几个属性。这个过程从 15 分钟缩短到 4 秒。感谢你的帮助。这对我们来说意义重大。
    【解决方案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);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-02-12
      • 1970-01-01
      • 2020-08-23
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      相关资源
      最近更新 更多