2017-08-09 87 views
3

我想利用Java的功能庫來過濾列表中的一些條目。如何通過Java中的多個屬性過濾列表?

我有一個Book對象列表,首先按Book ID排序,然後是修訂版號。下面的例子,我在列表中有九個Book對象。

Book: ID 1, Revision Number 1 
Book: ID 1, Revision Number 2 
Book: ID 1, Revision Number 3 
Book: ID 2, Revision Number 1 
Book: ID 2, Revision Number 2 
Book: ID 2, Revision Number 3 
Book: ID 3, Revision Number 1 
Book: ID 3, Revision Number 2 
Book: ID 3, Revision Number 3 

我想過濾列表,以便我只有每本書ID最高版本號。

Book: ID 1, Revision Number 3 
Book: ID 2, Revision Number 3 
Book: ID 3, Revision Number 3 

確實有Java的使用類似過濾器或比較,從而可以根據多個字段我來過濾,基於共同的價值(圖書ID)一些功能性的能力?我想盡量避免編寫自己的函數來循環使用Collection,並儘可能地進行過濾......有什麼建議嗎?

+0

也許一個'TreeSet'與一些比較器 – 2017-08-09 17:41:26

+0

你可以收集它來映射無線合併功能,是否可行? – ByeBye

+0

如果您使用的是java 8並知道要事先過濾的值,請參閱https://stackoverflow.com/questions/122105/what-is-the-best-way-to-filter-a-java-collection解決方案基於[Collection.removeIf()](https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-)可能是最好的適合你想要的東西 – csunday95

回答

4

什麼是這樣的:

List<Book> books = Arrays.asList(
     new Book(1, 2), 
     new Book(1, 3), 
     new Book(2, 2), 
     new Book(2, 3) 
); 

System.out.println(
    books.stream() 
      .collect(
        groupingBy(Book::getID, 
         maxBy(comparingInt(Book::getRevison)) 
        ) 
      ) 

);// {1=Optional[Book{ID=1, revison=3}], 2=Optional[Book{ID=2, revison=3}]} 

更新,如果在最後你只需要一個List<Book>只使用流的Map<Integer,Optinal<Book>>

.values().stream().map(Optional::get).collect(Collectors.toList())); 

的完整的例子值:

System.out.println(books.stream() 
       .collect(
         groupingBy(Book::getID, 
           maxBy(comparingInt(Book::getRevison)) 
         ) 
       ).values() 
       .stream() 
       .map(Optional::get) 
       .collect(Collectors.toList()) 
); 
+0

想要做我想做的事情,但我應該指定,它需要返回新的排序列表,這似乎不可能與此方法? – deanmau5

+0

@ deanmau5,這是可能的,請參閱我的更新的答案。 –

0

它不是基於一個以上的財產真正的過濾,但可以是你的問題的可行:

final Map<String, Book> books = list.stream().collect(
    Collectors.toMap(
     b -> b.getId(), 
     b -> b, 
     (b1, b2) -> { 
      if(b1.getNumber() > b2.getNumber()) { 
       return b1; 
      } 
      return b2; 
     }) 
); 

它會返回地圖包含ID爲重點,並隨書數量最多(具有唯一的ID )。

toMap收集器中,您可以添加merge function,這將決定在發生同一個鍵時發生碰撞時要執行的操作。在這種情況下,它會返回更高數量的書。

如果你想從那個電話values()收集。

+0

'groupingBy()'更好適合這個。看到我上面的評論。 – shmosel

+0

同意,但仍然需要爲Collectors.maxBy()創建比較器。 – ByeBye

+0

你說得對,我糾正了我的評論。 – shmosel