2016-11-23 23 views
10

O Map<K, List<V>> içine List<V> dönüştürmek kolaydır. Örneğin:Nasıl Java 8 akışları ve özel Listesi ve Harita tedarikçileri ile, Harita <K, List<V>> içine Listesini <V> dönüştürmek için?

public Map<Integer, List<String>> getMap(List<String> strings) { 
    return 
     strings.stream() 
      .collect(Collectors.groupingBy(String::length)); 
} 

Ama ben kendi List ve Maptedarikçileri ile yapmak istiyorum.

aklıma bu geldi:

public Map<Integer, List<String>> getMap(List<String> strings) { 
    return strings.stream() 
     .collect(Collectors.toMap(
      String::length, 
      item -> {List<String> list = new ArrayList<>(); list.add(item); return list;}, 
      (list1, list2) -> {list1.addAll(list2); return list1;}, 
      HashMap::new)); 
} 

Soru: bunu yapmanın daha kolay, daha az ayrıntılı, ya da daha verimli bir yolu var mı? Örneğin, böyle bir şey (hangi çalışmıyor):

return strings.stream() 
     .collect(Collectors.toMap(
      String::length, 
      ArrayList::new,      
      HashMap::new)); 

Ya ben sadece List tedarikçisi tanımlamak gerekirse, ancak Map tedarikçisi?

public Map<Integer, List<String>> getMap(List<String> strings) { 
    return strings.stream().collect(
     Collectors.groupingBy(String::length, HashMap::new, Collectors.toCollection(ArrayList::new)) 
    ); 
} 

kolektör groupingBy(classifier, mapFactory, downstream)mapFactory için o aranan haritanın bir tedarikçisi ileterek, haritanın türü aranıyor belirtmek için kullanılabilir:

+1

bir [ 'groupingBy'] (https://docs.oracle.com/javase/8/docs/api/java yoktur /util/stream/Collectors.html#groupingBy-java.util.function.Bir harita tedarikçisi alarak Function-java.util.function.Supplier-java.util.stream.Collector-) aşırı yük. – Tunaki

+0

Akışta, ilginizi çekebilecek üç arg toplama yöntemi var –

cevap

13

Aşağıdaki olabilir. Daha sonra, aynı anahtara gruplanmış elemanları toplamak için kullanılan alt koleksiyoncu, verilen tedarikçiden elde edilen bir koleksiyonu toplayan toCollection(collectionFactory)'dur.

Bu, döndürülen haritanın HashMap olduğundan ve listelerin her değerin ArrayList olduğundan emin olur. Belirli harita ve koleksiyon uygulamalarını döndürmek istiyorsanız, büyük olasılıkla yöntemin bu belirli türleri de döndürmesini istediğinizi unutmayın, böylece özelliklerini kullanabilirsiniz. Yalnızca bir koleksiyon tedarikçisi belirtin ve groupingBy Varsayılan haritayı tutmak istiyorsanız

, sadece yukarıdaki kodda tedarikçisi ihmal ve two arguments overload kullanabilirsiniz: Bir yan not olarak

public Map<Integer, List<String>> getMap(List<String> strings) { 
    return strings.stream().collect(
     Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new)) 
    ); 
} 

, bunun için genel bir yöntem olabilir:

public <K, V, C extends Collection<V>, M extends Map<K, C>> M getMap(List<V> list, 
     Function<? super V, ? extends K> classifier, Supplier<M> mapSupplier, Supplier<C> collectionSupplier) { 
    return list.stream().collect(
     Collectors.groupingBy(classifier, mapSupplier, Collectors.toCollection(collectionSupplier)) 
    ); 
} 

bu bildiriyle avantajı artık belirli HashMap olması kullanabilirsiniz olmasıdır sonuç olarak ArrayList ler veya LinkedHashMapLinkedLists s, arayan o isterse: o noktada,

HashMap<Integer, ArrayList<String>> m = getMap(Arrays.asList("foo", "bar", "toto"), 
     String::length, HashMap::new, ArrayList::new); 
LinkedHashMap<Integer, LinkedList<String>> m2 = getMap(Arrays.asList("foo", "bar", "toto"), 
     String::length, LinkedHashMap::new, LinkedList::new); 

ama, doğrudan kodda groupingBy ...

0

Ben kullanımı daha basit olabilir benzer bir durum vardı. Ben gibi çözülür:

Map<String, List<Object>> map = stringList.stream().collect(Collectors.toMap(str -> str, str -> populateList(str))); 

Ve populateList() geçerli:

private List<Object> populateList(final String str) { 
    ... 
    .... 
    List<Object> list = // dao.get(str); 
    return list; 
}