【问题标题】:Create an efficient ImmutableMap collector that holds an ImmutableList for each key创建一个高效的 ImmutableMap 收集器,为每个键保存一个 ImmutableList
【发布时间】:2015-02-12 21:48:43
【问题描述】:

我已经思考了一个星期,但我不太确定有什么方法可以做到这一点。我遇到的一个常见任务是为给定类型的值构建一个包含 ImmutableLists 的 ImmutableMap,如ImmutableMap<K,ImmutableList<V>>,我想通过一个收集器来完成它,以便我可以在流上利用它。

我在如下所示的博客上发现了这个很棒的 ImmutableMap 收集器。但是我希望 V 成为一个 ImmutableList,并且我希望传入流映射多个具有相同键的值,该键与具有 ImmutableList 值的所述键配对。我尝试过的每个实现都是次优的,而不是流式的,因为我一直在使用一个普通的 HashMap 保存 ImmutableList.Builder 值,当我完成填充时,我会循环遍历它并将其转换为 ImmutableList 值调用 build() 并将其放入新地图中。有什么想法吗?

public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>>
    toImmutableMap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper) {

    Supplier<ImmutableMap.Builder<K, V>> supplier =
        ImmutableMap.Builder::new;

    BiConsumer<ImmutableMap.Builder<K, V>, T> accumulator =
         (b, t) -> b.put(keyMapper.apply(t), valueMapper.apply(t));

    BinaryOperator<ImmutableMap.Builder<K, V>> combiner =
         (l, r) -> l.putAll(r.build());

    Function<ImmutableMap.Builder<K, V>, ImmutableMap<K, V>> finisher =
       ImmutableMap.Builder::build;

    return Collector.of(supplier, accumulator, combiner, finisher);
}

我希望实现具有...的标题

public static <T, K, V> Collector<T, ?, ImmutableMap<K, ImmutableList<V>>>

好的,感谢 fge 的帮助,我成功了!请参阅下面的答案。

【问题讨论】:

  • 等等,你用的是Guava,那你为什么不用Multimaps呢?它们也有不可变的版本
  • 呵呵,忘了这个家伙......以及它的不可变版本。让我玩这个,看看我能不能让它成为一个收藏家......

标签: java stream guava immutability collectors


【解决方案1】:

好的,我想我成功地利用了 ImmutableListMultimap 来完成这个!谢谢fg!

如果有人看到任何可以改进的地方(我认为组合器无法优化,但如果我错了请纠正我),请告诉我。

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) -> { 
        final ImmutableListMultimap<K, V> rightMap = r.build();
        rightMap.keySet().stream().forEach(k -> l.putAll(k, rightMap.get(k)));
        return l;
    };

    Function<ImmutableListMultimap.Builder<K, V>, ImmutableListMultimap<K, V>> finisher = ImmutableListMultimap.Builder::build;

    return Collector.of(supplier, accumulator, combiner, finisher);
}

更新 - 反映 fge 的建议并简化组合器

public static <T, K, V> Collector<T, ?, ImmutableMultimap<K, V>> toImmutableListMultimap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper) {

    Supplier<ImmutableMultimap.Builder<K, V>> supplier = ImmutableListMultimap.Builder::new;

    BiConsumer<ImmutableMultimap.Builder<K, V>, T> accumulator = (b, t) -> b
            .put(keyMapper.apply(t), valueMapper.apply(t));

    BinaryOperator<ImmutableMultimap.Builder<K, V>> combiner = (l, r) -> l.putAll(r.build());

    Function<ImmutableMultimap.Builder<K, V>, ImmutableMultimap<K, V>> finisher = ImmutableMultimap.Builder::build;

    return Collector.of(supplier, accumulator, combiner, finisher);
}

【讨论】:

  • 呃,不知道你为什么这样做; you can .putAll() a Multimap into another;因此,您现有的收集器应该按原样工作,只需将 ImmutableMap 替换为 ImmutableMultimap
  • 等等,你是说它应该被转换为 ImmutableMultiMap 吗?我不太确定你的意思是什么......
  • 我的意思是你的组合器可以简单地是(l, r) -&gt; l.putAll(r.build())——这个方法是由Multimap接口定义的,因此由继承它的ListMultimap定义
  • 看来你是对的,我没有看Multimap继承的方法。看起来它确实接受了整个地图。很划算。
  • 你仍然可以改进它;毕竟,ImmutableMultimap 仍然是Multimap,因此您无需将第三个类型参数声明为Immutable,同样,完成器也可以“向下转换”为Multimap 用于生产。毕竟ImmutableMultimap 上没有Multimap 没有的方法;好的,好吧,如果您需要 .get()s 来返回列表而不是集合,也许您需要 ListMultimap
猜你喜欢
  • 1970-01-01
  • 2015-02-21
  • 2016-09-14
  • 1970-01-01
  • 2013-09-12
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多