web-dev-qa-db-ja.com

Java 8でリストのリストをリストに変換する方法はありますか。

List<List<Object>>がある場合、Java 8の機能を使用して、それをどのようにして同じ反復順序ですべてのオブジェクトを含むList<Object>に変換できますか?

394
Sarah Szabo

flatMap を使用すると、内部リストを(Streamsに変換した後で)単一のStreamにフラット化してから、結果をリストにまとめることができます。

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());
723
Eran

flatmapが優れていますが、同じことを達成する他の方法があります

List<List<Object>> listOfList = ... // fill

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);
38
Saravana

Eclipse Collections からflatCollect()パターンを使うことができます。

MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);

リストをListから変更できない場合:

List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);

注:私はEclipseコレクションの寄稿者です。

14

flatMapStreamメソッドは確かにあなたのためにそれらのリストを平らにすることができます、しかしそれはelementのためのStreamオブジェクトを作成しなければなりません、そして結果のためのStream

あなたはそれらすべてのStreamオブジェクトを必要としません。これは、タスクを実行するための単純で簡潔なコードです。

// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);

ListIterableなので、このコードは forEachから継承された/ - Iterableメソッド (Java 8の機能)を呼び出します。

すべての要素が処理されるかアクションが例外をスローするまで、Iterableの各要素に対して指定されたアクションを実行します。その順序が指定されている場合、アクションは反復の順序で実行されます。

そしてListIteratorは項目を順番に返します。

Consumerの場合、このコードはメソッド参照(Java 8機能)をJava 8より前のメソッド List.addAll に渡して、内部リスト要素を順次追加します。

指定されたコレクションの反復子によって返される順序で、指定されたコレクション内のすべての要素をこのリストの末尾に追加します(オプションの操作)。

13
rgettman

@Saravanaが述べたように、

フラットマップの方が優れていますが、それを実現する方法は他にもあります。

 listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
 });

まとめると、以下のように同じことを達成するにはいくつかの方法があります。

private <T> List<T> mergeOne(Stream<List<T>> listStream) {
    return listStream.flatMap(List::stream).collect(toList());
}

private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
    List<T> result = new ArrayList<>();
    listStream.forEach(result::addAll);
    return result;
}

private <T> List<T> mergeThree(Stream<List<T>> listStream) {
    return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
    });
}

private <T> List<T> mergeFour(Stream<List<T>> listStream) {
    return listStream.reduce((l1, l2) -> {
        List<T> l = new ArrayList<>(l1);
        l.addAll(l2);
        return l;
    }).orElse(new ArrayList<>());
}

private <T> List<T> mergeFive(Stream<List<T>> listStream) {
    return listStream.collect(ArrayList::new, List::addAll, List::addAll);
}
6
Hearen

List<Documents>のようなもう1つのシナリオを説明したいだけです。このリストにはList<Excel>List<Word>List<PowerPoint>のような他の文書のもう少しのリストがあります。だから構造は

class A {
  List<Documents> documentList;
}

class Documents {
  List<Excel> excels;
  List<Word> words;
  List<PowerPoint> ppt;
}

あなたが文書からのみExcelを反復したいのであれば今、以下のような何かをしてください..

そのため、コードは

 List<Document> documentList = new A().getDocumentList();

 //check documentList as not null

 Optional<Excel> excelOptional = documentList.stream()
                         .map(doc -> doc.getExcel())
                         .flatMap(List::stream).findFirst();
 if(excelOptional.isPresent()){
   Excel exl = optionalExcel.get();
   // now get the value what you want.
 }

コーディング中にこれで誰かの問題を解決できることを願っています...

3
Kushwaha

Eranの答えを拡張したものが一番の答えでした。リストのレイヤーがたくさんある場合は、フラットマッピングを続けることができます。

これには、必要に応じてレイヤーを下に移動するときにも便利なフィルタリング方法が用意されています。

たとえば、次のとおりです。

List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...

List<Object> objectList = multiLayeredList
    .stream()
    .flatmap(someList1 -> someList1
        .stream()
        .filter(...Optional...))
    .flatmap(someList2 -> someList2
        .stream()
        .filter(...Optional...))
    .flatmap(someList3 -> someList3
        .stream()
        .filter(...Optional...))
    ...
    .collect(Collectors.toList())

これは、SQLでSELECTステートメント内にSELECTステートメントを持つことに似ています。

0
cody.tv.weber

リストのリストをリストに変換するメソッド:ListOfLists.stream()。flatMap(List :: stream).collect(Collectors.toList());例1

    public class ConvertListOfListsToList {
        public static void main(String[] args) {
            List<String> StringList = Arrays.asList("Protijayi", "Gini", "Gina");
            System.out.println(StringList);
            List<List<String>> ListOfLists = new ArrayList<>();
            ListOfLists.add(StringList);

            System.out.println("ListOfLists => " + ListOfLists);

            // Now let's do this in Java 8 using FlatMap
            List<String> flatMapList = ListOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

            System.out.println("FlatList =>  " + flatMapList);
/*
ListOfLists => [[Protijayi, Gini, Gina]]
FlatList =>  [Protijayi, Gini, Gina]
*/
        }

    }
0
Soudipta Dutta

これにはflatmapを使用できます。以下のコードを参照してください:

 List<Integer> i1= Arrays.asList(1, 2, 3, 4);
 List<Integer> i2= Arrays.asList(5, 6, 7, 8);

 List<List<Integer>> ii= Arrays.asList(i1, i2);
 System.out.println("List<List<Integer>>"+ii);
 List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
 System.out.println("Flattened to List<Integer>"+flat);
0
Pratik Pawar