2014-04-11 3 views
11

है मैं एक List<Foo> है और एक अमरूद Multimap<String, Foo> जहाँ हम उनके Collection<String> getTags() समारोह के प्रत्येक टैग द्वारा Foo की समूहीकृत किया है चाहता हूँ।स्पष्ट तरीका मद के एक संपत्ति के द्वारा एक संग्रह है कि अपने आप में एक संग्रह

मैं जावा 8 का उपयोग कर रहा हूं, इसलिए लैम्बडा और विधि संदर्भ ठीक/प्रोत्साहित हैं।

उदाहरण के लिए अगर मेरे पास है:

foo1, tags=a,b,c 
foo2, tags=c,d 
foo3, tags=a,c,e 

मैं मिलेगा एक Multimap<String, Foo> साथ:

Multimap<String, Foo> map = list.stream().collect(
    ImmutableMultimap::builder, 
    (builder, value) -> value.getTags().forEach(tag -> builder.put(tag, value)), 
    (builder1, builder2) -> builder1.putAll(builder2.build()) 
).build(); 

यह:

a -> foo1, foo3 
b -> foo1 
c -> foo1, foo2, foo3 
d -> foo2 
e -> foo3 
+2

चूंकि गुवा 21 में एक अंतर्निहित [ImmutableListMultimap.toImmutableListMultimap] है (https://google.github.io/guava/releases/21.0/api/docs/com/google/common/collect/ImmutableListMultimap.html# toImutableListMultimap-java.util.function.Function-java.util.function.Function-) कलेक्टर। –

उत्तर

12

आप इस के लिए कस्टम कलेक्टर का उपयोग कर सकते कारण नहीं है ई अतिरिक्त दुष्प्रभाव (इस पर here देखें), समवर्ती और अधिक मूर्खतापूर्ण है।

तुम भी एक पूर्ण कलेक्टर में इन तदर्थ lambdas निकाल सकते हैं, कुछ इस तरह:

public static <T, K> Collector<T, ?, Multimap<K, T>> toMultimapByKey(Function<? super T, ? extends Iterable<? extends K>> keysMapper) { 
    return new MultimapCollector<>(keysMapper); 
} 

private static class MultimapCollector<T, K> implements Collector<T, ImmutableMultimap.Builder<K, T>, Multimap<K, T>> { 
    private final Function<? super T, ? extends Iterable<? extends K>> keysMapper; 

    private MultimapCollector(Function<? super T, ? extends Iterable<? extends K>> keysMapper) { 
     this.keysMapper = keysMapper; 
    } 

    @Override 
    public Supplier<ImmutableMultimap.Builder<K, T>> supplier() { 
     return ImmutableMultimap::builder; 
    } 

    @Override 
    public BiConsumer<ImmutableMultimap.Builder<K, T>, T> accumulator() { 
     return (builder, value) -> keysMapper.apply(value).forEach(k -> builder.put(k, value)); 
    } 

    @Override 
    public BinaryOperator<ImmutableMultimap.Builder<K, T>> combiner() { 
     return (b1, b2) -> b1.putAll(b2.build()); 
    } 

    @Override 
    public Function<ImmutableMultimap.Builder<K, T>, Multimap<K, T>> finisher() { 
     return ImmutableMultimap.Builder<K, T>::build; 
    } 

    @Override 
    public Set<Characteristics> characteristics() { 
     return Collections.emptySet(); 
    } 
} 

तब संग्रह इस प्रकार दिखाई देगा:

Multimap<String, Foo> map = list.stream().collect(toMultimapByKey(Foo::getTags)); 

तुम भी लौट सकते हैं EnumSet.of(Characteristics.UNORDERED)characteristics() विधि से यदि आपके लिए ऑर्डर महत्वपूर्ण नहीं है। यह आंतरिक संग्रह मशीनरी अधिनियम को अधिक कुशलता से बना सकता है, खासकर समानांतर कमी के मामले में।

7
ImmutableMultimap.Builder<String, Foo> builder = ImmutableMultimap.builder(); 
list.forEach(foo -> foo.getTags().forEach(tag -> builder.put(tag, foo)); 
return builder.build(); 
+0

अच्छा, और एक अच्छा स्थिर सहायक में लपेटा जा सकता है। अगर कुछ कम है तो उत्सुक है। –

+0

गुवा के इस संस्करण में नहीं। –

संबंधित मुद्दे