2017-02-03 3 views
2

属性のJava 8:反復およびグループは、オブジェクトに基づいて、リストからオブジェクトをすることは、私は(GlobalBooks)のリストを持っている

import java.util.ArrayList; 
import java.util.List; 

public class Main { 

    public static void main(String[] args) { 

     GlobalBooks globalBooks = new GlobalBooks(); 

     List<Book> bookList = new ArrayList<Book>(); 


     Book book = new Book(); 
     List<BookContent> bookContents = new ArrayList<BookContent>(); 

     book.setBookName("A"); 
     BookContent content = new BookContent(); 
     content.setDescription("December 2016"); 
     content.setComponentID(20l); 
     bookContents.add(content); 

     content = new BookContent(); 
     content.setDescription("January 2016"); 
     content.setComponentID(30l); 
     bookContents.add(content); 

     content = new BookContent(); 
     content.setDescription("Febuary 2016"); 
     content.setComponentID(40l); 
     bookContents.add(content); 
     book.setContents(bookContents); 

     bookList.add(book); 


     book = new Book(); 
     bookContents = new ArrayList<BookContent>(); 

     book.setBookName("B"); 
     content = new BookContent(); 
     content.setDescription("December 2016"); 
     content.setComponentID(20l); 
     bookContents.add(content); 

     content = new BookContent(); 
     content.setDescription("January 2016"); 
     content.setComponentID(30l); 
     bookContents.add(content); 

     content = new BookContent(); 
     content.setDescription("Febuary 2016"); 
     content.setComponentID(40l); 
     bookContents.add(content); 
     book.setContents(bookContents); 

     bookList.add(book); 

     globalBooks.setBooks(bookList); 


     System.out.println(globalBooks); 


    } 

} 

以下のようになりますどの私はglobalBooks応答をストリーミングすることができたJava 8の機能を探していますし、 BooksContentの説明フィールドに基づいてBooks of Listのマップを収集します。

Map<String,List<Books>>つまり、同じ説明のすべての書籍は説明でグループ化する必要がありますか?

私はこれを通常のjava経由で行うことができますが、コードはあまりにも面倒で不安定になります。

+0

各書籍には内容の異なる複数のコンテンツがあるため、各書籍を複数のマップエントリに表示する必要がありますか? –

+0

Guava 'MultiMap'を使った同様の質問:[アイテムのプロパティのコレクションによってインデックスを作成する最もクリーンな方法はコレクションです](http://stackoverflow.com/questions/23003754/cleanest-way-to-index-a -collection-by-a-of-the-items-of-its-is-a) – MikaelF

答えて

6

各書籍には説明が異なる複数のコンテンツがあるため、各書籍を複数のマップエントリに表示する必要があります。ですから、flatMapを使用して、各BookContent、具体的にはDescription + Bookペアのストリーム要素を作成します。次いでCollectors.groupingByで通常通りマップに収集:

Map<String,List<Book>> result = globalBooks.getBooks().stream().flatMap(
     (Book b) -> b.getContents().stream().map(
      (BookContent bc) -> new Pair<>(bc.getDescription(), b) 
     ) 
    ).collect(Collectors.groupingBy(
     Pair::getKey, 
     Collectors.mapping(Pair::getValue, Collectors.toList()) 
    )); 

注:私は上記で使用している

ペアクラスjavafx.util.Pairからです。ただし、AbstractMap.SimpleEntry、自分のPairクラス、または2つのオブジェクトを保持できるコレクションデータ型を簡単に使用できます。

Map<String, List<String>> result = bookList.stream().flatMap(b -> b.getContents().stream()) 
    .collect(Collectors.toMap(str -> str, str -> bookList.stream() 
    .filter(b -> b.getContents().contains(str)) 
    .collect(Collectors.toList()), (a, b) -> {a.addAll(b);return a;})); 

あなたが並列でこれを実行したい場合は、単純なCollectors.toConcurrentMapとコレクタを置き換える:

1

別の解決策は、これが仕事をする

Map<String,List<Book>> result = new HashMap<String, List<Book>>(); 

    globalBooks.getBooks().stream().forEach(book->{ 

     book.getContents().stream().forEach(bookContent->{ 

      result.computeIfAbsent(bookContent.getDescription(),(list)->new ArrayList<Book>()).add(book); 
     }); 
    }); 
+2

このコードは不必要に副作用を使用します。並行して実行すると、HashMapのスレッドセーフではない結果が不正確になり、必要な同期を追加すると競合が発生します。 –

+1

私はcomputeIfAbsentを使った標準のJavaループが書く方が簡単で、読みやすく、(おそらく)実行が速いことを示しているので、この答えは良いと思います。しかし、前のコメントで説明したように、標準の 'for(item:collection)'ループの 'Stream.forEach'を使うべきではありません。 –

1

である可能性があります。

関連する問題