2016-08-18 32 views
-3

我正在尋找使用Java流來解決這種類型的問題:使用具有組合集合的Java流

我有一個庫對象列表。

Library類包含剖面圖。部分包含BookShelf對象的列表。 BookShelf包含一個Book對象的Map。

class Library { 
    Map<String, Section> sections = new HashMap<String, Section>(); 
    String name; 
    public String toString() { 
     return name; 
    } 
} 

class Section { 
    List<BookShelf> bookShelves = new ArrayList<BookShelf>(); 
} 

class BookShelf { 
    Map<String, Book> books = new HashMap<String, Book>(); 
} 

class Book { 
    String name; 
    Book(String name) { 
     this.name = name; 
    } 
} 

我想知道的是所有具有名爲「Java 8」的書籍的圖書館對象。我認爲這是一個可以使用流來回答的查詢,然而,編碼各種流調用我得到一個Book對象集合,而不是根Library對象。

是否適合使用嵌入對象和集合的流?我將如何實現這一目標?

下面是一個簡單的代碼,使用傳統的循環中找到了答案:

List<Library> libraries = new ArrayList<Library>(); 

Library lib = new Library(); 
lib.name = "Houston Central"; 
libraries.add(lib); 

Section section = new Section(); 
lib.sections.put("Reference", section); 

BookShelf shelf = new BookShelf(); 
section.bookShelves.add(shelf); 

Book book = new Book("Java 8"); 
shelf.books.put("Java 8", book); 

book = new Book("Java 7"); 
shelf.books.put("Java 7", book); 


/* 
* Search for a Library containing a specific book 
* using traditional loops. 
*/ 
for(Library library : libraries) { 
    for (Section sec : library.sections.values()) { 
     for (BookShelf bookShelf : sec.bookShelves) { 
      for (Book b : bookShelf.books.values()) { 
       if (b.name.equals("Java 8")) { 
        System.out.println("Book is contained in Library " + library); 
       } 
      } 
     } 
    } 
} 
+2

請告訴我們一些代碼。另外,你到目前爲止嘗試過什麼? – Sartorius

+0

下面是一些使用傳統循環的測試代碼,但我很快就迷失了,試圖用java 8流來實現。 –

回答

0

流是否適合與否可能是口味和可讀性偏好的問題。在我看來,流代碼和lambda表達式並不能提供最易讀的代碼,但也許是你學習的東西。在任何情況下,基本方法是根據是否存在標題爲「Java 8」的書籍過濾庫流,並將滿足過濾謂詞的庫作爲集合返回。過濾本身要求將每個庫變成書籍流,這需要兩個平面映射操作。然後,我使用anyMatch匹配書名並終止給定庫的流。你可以並行化我所期望的過程,但是我並沒有在並行數據流上做很多事情。

下面提供的示例將搜索過程外化。更合適的面向對象的方法將包括Section和BookShelf類中的圖書搜索功能,這將大大提高可讀性。

請記住,您正在順序搜索一本書,並且順序搜索速度很慢。順序搜索是O(n),而HashMap索引搜索是O(1)。我會在BookShelf類中包含一個索引。我提供了一個下面的順序搜索算法的示例(未測試)。

public Collection<Library> hasBook(Collection<Library> libraries, String title) { 
    return libraries.stream() 
     .filter(x->x.sections() 
       .stream() 
       .flatMap(y->y.bookShelves() 
         .stream() 
         .flatMap(z->z.books().stream())) 
       .anyMatch(b->b.title().equals(title))) 
     .collect(Collectors.toList()); 
} 
+0

謝謝約翰,這增加了我的理解。上面的代碼是按原樣運行的,但是在使用Map集合的地方,我加了.values()後綴以獲取List以獲取流。 我想知道如何添加測試程序! –

0

使用約翰莫里斯與一個調整,支持地圖解決方案解決了這個問題:

/* 
* Using Streams 
*/ 
public static Collection<Library> hasBook(Collection<Library> libraries, String title) { 
    return libraries.stream() 
     .filter(x->x.sections.values() 
       .stream() 
       .flatMap(y->y.bookShelves 
         .stream() 
         .flatMap(z->z.books.values().stream())) 
       .anyMatch(b->b.name.equals(title))) 
     .collect(Collectors.toList()); 
} 

調用代碼:

/* 
* Search using streams 
*/ 
Collection<Library> libs = hasBook(libraries, "Java 8"); 
for (Library l : libs) { 
    System.out.println("Book is contained in Library (via streams) " + l); 
}