簡體   English   中英

使用地圖中的值過濾pojos流

[英]Filtering a stream of pojos using values from a map

我有這個pojo(這是一個例子,而不是真實的例子):

Book {
  String name;
  Map<String, String> properties;
}

以及它們的清單:

List<Book> library;

TheBook1, {["lang", "pt-br"],["type","romance"],["author","John"]}
TheBook2, {["lang", "en-US"],["type","fiction"],["author","Brian"],["translation","pt-br,es"}

假設我有一個Library集合,並且我有一個包含搜索條件的地圖,例如:

Map<String, String> criteria = new HashMap<>();
criteria.put(BOOK_TYPE, "romance");
criteria.put(BOOK_LANG, "pt-br");

我如何為庫流編寫過濾謂詞,以便搜索符合所提供標准的所有書籍? 匹配必須是現在的鍵和值的精確字符串匹配。

像這樣的東西:

Set<Book> result = library.stream()
.filter(b-> b.getProperties() **????**)
.collect(Collectors.toSet());

你可以簡單地:

List<Book> books = 
    library.stream()
           .filter(b -> b.properties.entrySet().containsAll(criteria.entrySet()))
           .collect(Collectors.toList());

這將過濾書籍,只保留其屬性包含所有給定條件的書籍。 檢查是使用containsAll完成的,這意味着它將保留包含完全給定條件的屬性(通過條目的相等性進行匹配,因此鍵和值都相等)。

library是一個List<Book>我猜?


試想一下如何在不使用Java8 / Streams的情況下編寫謂詞。 然后將謂詞放在filter方法中。

即:

Book b = ...;
boolean matches = false;
if(b.properties != null) {
  for(Entry<String,String> e : b.properties) {
    if(e.getKey().equals("foo") && e.getValue().length > 3) {
      matches = true;
      break;
    }
  }
}

(我知道這個過濾器可以寫得更簡單,如果需要可以優化它)

現在創建一個方法:

public static boolean myPredicate(Book b) {
  if(b.properties != null) {
    for(Entry<String,String> e : b.properties) {
      if(e.getKey().equals("foo") && e.getValue().length > 3) {
        return true;
      }
    }
  }
  return false;
}

然后將其放在您的流中:

Set<Book> result = library.stream()
  .filter(MyClass::myPredicate)
  .collect(Collectors.toSet());

您也可以將其直接放在filter方法中:

Set<Book> result = library.stream()
  .filter(b -> {
    if(b.properties != null) {
      for(Entry<String,String> e : b.properties) {
        if(e.getKey().equals("foo") && e.getValue().length > 3) {
          return true;
        }
      }
    }
    return false;
  })
  .collect(Collectors.toSet());

順便說一句:你不應該需要toSet收集器。 只需創建一個List 應該更有效率。

您可以使用以下語法:

Set<Book> filteredBooks = library
    .stream()
    .filter((a) -> {
                boolean answer;
                for(Entry<Integer, String> filter : filters.entrySet())
                    if (!isTrue(a, filter.getValue().getProperty())) return false;
                return true;
                   })
        .collect(Collectors.toCollection(HashSet::new));

雖然filters實際上是您擁有的標准Map get(1) ”是你的第一個標准等。我使用isTrue作為一種方法,為通過標准的書籍返回boolean 如您所見,您可以使用多個條件。 沒問題。

祝好運!

如上所述 lambda表達式的主體可以是單個表達式,也可以是語句塊。 所以你可以像這樣編寫你的謂詞:(t) - > {//語句1; // statement2; //返回結果;}。

Set<Book> result = library.stream()
            .filter( b -> {
    for (Map.Entry<String, String> entry : criteria.entrySet()) {
        String key = entry.getKey();
        if (!(b.getProperties().get(key) != null && b.getProperties().get(key).equals(entry.getValue()))) return false;
    }
    return true;
})
.collect(Collectors.toSet());

否則,您可以使用其謂詞格式替換您的條件:

Set<Book> result3 = library.stream()
            .filter( b -> b.getProperties().get("BOOK_TYPE").equals("romance") && b.getProperties().get("BOOK_LANG").equals("Pt-Br"))
            .collect(Collectors.toSet());

要么,

Predicate<Book> bookType = b -> b.getProperties() != null &&  b.getProperties().get("BOOK_TYPE") != null && b.getProperties().get("BOOK_TYPE").equals("romance");
Predicate<Book> bookLang = b -> b.getProperties() != null && b.getProperties().get("BOOK_LANG") != null && b.getProperties().get("BOOK_LANG").equals("Pt-Br");
Set<Book> result3 = library.stream()
            .filter(bookType)
            .filter(bookLang)
            .collect(Collectors.toSet());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM