[英]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.