web-dev-qa-db-ja.com

順序を維持しながら、List <P>の要素をMap <K、List <V >>にどのようにグループ化しますか?

Google PlacesAPIから取得したGooglePlaceSummaryオブジェクトのリストがあります。それらをGoogleプレイスIDで収集してグループ化しますが、要素の順序も保持したいと思います。私がうまくいくと思ったのは:

_Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
            places.stream()
                  .collect(Collectors.groupingBy(
                          PlaceSummary::getPlaceId,
                          LinkedHashMap::new,
                          Collectors.mapping(PlaceSummary::getPlaceId, toList())
                  ));
_

しかし、それはコンパイルすらしません。 コレクターに関するJava APIドキュメント によるとそうあるべきです。

以前、私はこのコードを持っていました:

_    Map<String, List<PlaceSummary>> placesGroupedByPlaceId = places.stream()
            .collect(Collectors.groupingBy(PlaceSummary::getPlaceId));
_

ただし、StreamsAPIの標準の.collect()は、後続のHashMapの要素の順序を保持しません(明らかにHashMapsは順序付けされていないため)。マップが各バケットの挿入順序でソートされるように、出力をLinkedHashMapにしたいと思います。

ただし、私が提案したソリューションはコンパイルされません。まず、関数ではないと言っているので、_PlaceSummary::getPlaceId_を認識しません-私はそれを知っていますが。次に、_LinkedHashMap<Object, Object>_をMに変換できないと表示されます。Mは汎用コレクションであると想定されているため、受け入れる必要があります。

Java Stream APIを使用してリストをLinkedHashMapに変換するにはどうすればよいですか?それを行うための簡潔な方法はありますか?理解するのが難しすぎる場合は、古いものに頼ることができます学校のJava8以前のメソッド。

ListをLinkedHashMapに変換する際の別のStack Overflowの回答 があることに気付きましたが、具体的に繰り返し処理しているオブジェクトを「this」収集する必要があるため、これには解決策がありません。

18
James Murphy

あなたは本当にあなたが望むものに近づいています:

_Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
            places.stream()
                  .collect(Collectors.groupingBy(
                          PlaceSummary::getPlaceId,
                          LinkedHashMap::new,
                          Collectors.mapping(Function.identity(), Collectors.toList())
                  ));
_

_Collectors.mapping_メソッドでは、場所IDではなくPlaceSummaryインスタンスを指定する必要があります。上記のコードでは、Function.identity()を使用しました。このコレクターは値を作成するために使用されるため、場所自体(IDではなく)を累積する必要があります。

Collectors.toList()の代わりにCollectors.mapping(Function.identity(), Collectors.toList())を直接書き込むことができることに注意してください。

これまでのコードは、実際には_Map<String, List<String>>_を作成しているため、コンパイルされません。各IDのIDを蓄積しています(これは非常に奇妙です)。


これは一般的なメソッドとして記述できます。

_private static <K, V> Map<K, List<V>> groupByOrdered(List<V> list, Function<V, K> keyFunction) {
    return list.stream()
                .collect(Collectors.groupingBy(
                    keyFunction,
                    LinkedHashMap::new,
                    Collectors.toList()
                ));
}
_

次のように使用します。

_Map<String, List<PlaceSummary>> placesGroupedById = groupByOrdered(places, PlaceSummary::getPlaceId);
_
19
Tunaki

最終的なコレクターについて少し混乱したと思います。これは、各マップ値に必要なものを表すだけです。元のオブジェクトのリストが必要なだけなので、セカンダリmappingコレクターを用意する必要はありません。

    Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
          places.stream()
                .collect(Collectors.groupingBy(PlaceSummary::getPlaceId,
                                               LinkedHashMap::new,
                                               Collectors.toList()));
4
RealSkeptic

順序を維持しながらグループ化が必要で、関数(削減)を適用する場合は、おそらくカウントして、このようなものを使用します。

final Map<Integer,Long>map=stream.collect(Collectors.groupingBy(function
   ,LinkedHashMap::new
   ,Collectors.collectingAndThen(Collectors.counting(),Function.identity()))
 )
0
chiperortiz
/**
 * I have written this code more generic, if you want then you can group based on any * 
 * instance variable , id, name etc via passing method reference.
**/

class Student {
    private int id;
    private String name;
    public Student(int id, String name) {this.id = id;this.name = name;}
    /**
     * @return the id
     */
    public int getId() {return id;}
    /**
     * @param id
     *            the id to set
     */
    public void setId(int id) {this.id = id;}
    /**
     * @return the name
     */
    public String getName() {return name;}
    /**
     * @param name
     *            the name to set
     */
    public void setName(String name) {this.name = name;}
}

public class StudentMain {

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student(1, "Amit"));
        list.add(new Student(2, "Sumit"));
        list.add(new Student(1, "Ram"));
        list.add(new Student(2, "Shyam"));
        list.add(new Student(3, "Amit"));
        list.add(new Student(4, "Pankaj"));

        Map<?, List<Student>> studentById = groupByStudentId(list,
                Student::getId);
        System.out.println(studentById);

       Map<?, List<Student>> studentByName = groupByStudentId(list,
                Student::getName);
        System.out.println(studentByName);

    }

    private static <K, V> Map<?, List<V>> groupByStudentId(List<V> list,
            Function<V, K> keyFunction) {
        return list.stream().collect(
                Collectors.groupingBy(keyFunction, HashMap::new,
                        Collectors.toList()));
    }
}
0
Ram Dular