2016-11-23 9 views
10

List<V>Map<K, List<V>>に簡単に変換できます。たとえば、次のようにリスト<V>をどのようにマップ<K, List<V>に変換すると、Java 8ストリームとカスタムリストおよびマップサプライヤを備えていますか?

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

しかし、私は私自身のListMapサプライヤーでそれをやってみたいです。

私はこれが出ている:

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

質問:はそれをやってのより容易な、より少ない冗長、またはより効率的な方法はありますか?例えば(動作しない)このような、何か:

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

そして、何私はListサプライヤーではなくMapサプライヤーを定義する必要がある場合は?

+1

[ 'groupingBy']があります(https://docs.oracle.com/javase/8/docs/api/java /util/stream/Collectors.html#groupingBy-java.util.function。Function-java.util.function.Supplier-java.util.stream.Collector-)オーバーロードしてマップサプライヤを取得します。 – Tunaki

+0

ストリームに興味のある3つの引数収集メソッドがあります –

答えて

13

次を持つことができます:

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

コレクタgroupingBy(classifier, mapFactory, downstream)はそれをmapFactoryのための希望のマップのサプライヤーを渡すことで、指名手配されたマップのタイプを指定するために使用することができます。次に、同じキーにグループ化された要素を収集するために使用されるダウンストリームコレクタは、toCollection(collectionFactory)であり、指定されたサプライヤから取得したコレクションに収集することができます。

これは、返されるマップがHashMapであり、各値のリストがArrayListであることを確認します。マップとコレクションの特定の実装を返す場合は、それらの特定の型も返すようにしたいので、そのプロパティを使用できます。

あなただけのコレクションサプライヤを指定し、groupingByデフォルトのマップを維持したい場合は、あなただけ上記のコードでサプライヤーを省略しtwo arguments overloadを使用することができます。

サイドノートとして
public Map<Integer, List<String>> getMap(List<String> strings) { 
    return strings.stream().collect(
     Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new)) 
    ); 
} 

、あなたはそのための一般的な方法を持つことができます:

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

この宣言の利点は、あなたが今の特定HashMapを持つようにそれを使用することができるということです結果としてArrayList S、又はLinkedHashMapLinkedListsのS、発信者がそれを望む場合:

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); 

しかし、その時点で、直接コードでgroupingByを使用する方が簡単であってもよい...

0

Iは同様の状況を抱えていた。私はそれが好き解決:

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

そしてpopulateList()は次のとおりです。

private List<Object> populateList(final String str) { 
    ... 
    .... 
    List<Object> list = // dao.get(str); 
    return list; 
} 
関連する問題