2015-04-02 97 views
4

爲了提高效率,我經常遇到需要多圖的地圖的情況。我更喜歡使用Guava的ImmutableMapImmutableMultimap來完成這個。創建ImmutableMap <P,ImmutableMultimap <C,V>>流收集器

我借用併爲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) { 

} 

由於番石榴不可變集合建設者不允許查詢,我發現自己使用可變包含HashMap是能夠查找先前捕獲的值,所以我只會創建一個新的ImmutableMultimap當P關鍵是不存在的。但是這個過程很快就令人眩暈。

有沒有一種有效的方法來做到這一點?

回答

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

這麼多漂亮;) – muued 2015-04-02 18:41:22

+0

我喜歡這個答案,並希望它的工作。我試圖找出與泛型編譯錯誤... – tmn 2015-04-02 19:31:21

+0

@ThomasN。這與java 1.8.0_25編譯很好。你使用eclipse編譯器嗎? – Misha 2015-04-02 19:40:43

2

我沒有看到使用番石榴建造者的外部地圖的方法。然而,涉及可變的hashmaps並不是真的令人目不暇接,是嗎? 使用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); 
} 
相關問題