2014-12-14 2 views
2

저는 일주일 동안이 문제에 관심을 가졌습니다.이 작업을 수행 할 방법이 확실하지 않습니다. 내가 실행중인 일반적인 작업은 주어진 유형의 값에 대해 ImmutableMap<K,ImmutableList<V>>과 같이 ImmutableLists를 포함하는 ImmutableMap을 작성하는 것이며 콜렉터를 통해 수행하므로 스트림에서 활용할 수 있습니다.각 키에 대해 ImmutableList를 보유하는 효율적인 ImmutableMap 수집기 만들기

아래의 블로그에서이 멋진 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의 도움으로 성공적으로 감사했다! 아래 답변을 참조하십시오.

+2

대기를 단순화, 그렇게하지 않는 이유는'Multimap's를 사용 하는가? 그들 중 불변 버전이 있습니다 – fge

+0

허,이 사람에 대해 잊어 버렸습니다 ... 그리고 그것의 불변 버전입니다. 이걸 가지고 놀아 내가 콜렉터로 만들 수 있는지 알아 보자. – tmn

답변

0

좋아요, 나는 이것을 성공적으로 수행하기 위해 ImmutableListMultimap을 성공적으로 사용했다고 생각합니다! 고마워요.

아무도 개선 할 수있는 것을 본다면 (나는 잘못하면 combiner를 최적화 할 수는 없지만 나를 수정한다고 생각합니다.) 알려 주시기 바랍니다.

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

어째서 왜 이런 식으로하는지 확신 할 수 없다. [다른 사람에게'.putAll()'Multimap'을 할 수 있습니다.] (http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Multimap.html #putAll (com.google.common.collect.Multimap)); 그래서 당신의 기존 컬렉터는'ImmutableMap'을'ImmutableMultimap'으로 대체하여 그대로 작동해야합니다. – fge

+0

잠깐, 당신은 ImmutableMultiMap에 캐스트해야한다고 말하고 있습니까? 나는 당신이 그렇지 않다는 것을 확실히 모르겠다 ... – tmn

+1

당신의 결합자는 단순히'(l, r) -> l.putAll (r.build())'일 수있다 -이 방법은' 그러므로 그것을 상속하는'ListMultimap'에 의한 Multimap 인터페이스. – fge