web-dev-qa-db-ja.com

List <V>をMap = K、List <V >>に、Java 8ストリームとカスタムリストおよびマップサプライヤで変換する方法は?

簡単に変換できますList<V> into Map<K, List<V>>。例えば:

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

しかし、私は自分のListMapsuppliersでそれをやりたいです。

私はこれを思いつきました:

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サプライヤーを定義する必要がない場合はどうなりますか?

22
MarcG

次のものがあります。

_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 of ArrayListsを結果として、またはLinkedHashMap of LinkedListssを結果として使用できることです。それ:

_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を直接使用する方が簡単かもしれません...

28
Tunaki

同様の状況がありました。私はそれを次のように解決しました:

_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;
}
_
0
Arvind SJ