我收集了< code >
| isNew | isSoldOut
--------------------------------
predicate 1: | false | false
predicate 2: | false | true
predicate 3: | true | false
predicate 4: | true | true
我想找到“每种类型中的一种”,尽管我想找到产品集合中每个谓词的第一个匹配项。
目前我的代码如下:
java prettyprint-override">List<Product> products = getProducts();
List<Predicate<Product>> predicates = getPredicates();
List<Product> result = predicates.stream()
.flatMap(predicate -> products.stream().filter(predicate).findFirst().stream())
.collect(Collectors.toList());
但这当然会多次迭代产品集合,这是不需要的,因为在我的例子中,我有100000个产品和64个谓词,并且需要很长时间。
在我的特例中,谓词是互斥的:如果一个谓词返回true,那么对于该特定产品,所有其他谓词都可以跳过。因为我使用了< code>findFirst,所以对于所有其他产品,可以跳过这个谓词。
我想知道是否可以迭代产品集合,并根据所有谓词检查每个产品一次。
如果我理解正确,你正在寻找这样的东西:
List<Product> results = products.stream()
.filter(prod -> predicates.stream()
.anyMatch(pred -> pred.test(prod)))
.collect(Collectors.toList());
您当前的解决方案将对集合进行多次迭代,但是由于< code>findFirst是一个短路操作符,它将在找到匹配项后立即停止。你是否对它进行了基准测试,以确保它不够好?
另一种方法是使用有状态过滤器(见本文顶部答案):
public static Predicate<Product> matchAndDiscard(final List<Predicate<Product>> predicates) {
final Set<Predicate<Product>> remaining = new HashSet<>(predicates);
return product -> {
final var match = remaining.stream().filter(pred -> pred.test(product)).findFirst();
match.ifPresent(remaining::remove);
return match.isPresent();
};
}
很像@Chaosfire的方法,但包含在过滤器函数中的状态。如果您相信所有谓词都会被至少一个产品匹配,您还可以通过将流限制为谓词的数量来节省一些时间,如下所示:
final var predicates = getPredicates()
final var result = getProducts().stream()
.filter(matchAndDiscard(predicates))
.limit(predicates.size())
.toList()
在您当前的解决方案中,您将“水平”遍历产品:
--> products
pred1: ffffffffffffft
pred2: fffft
pred3: ffffffffffffffft
pred4: ft
etc.
另一种方法是进行“垂直”遍历:
products
pred1: | ffffffffffffft
pred2: | fffft
pred3: v ffff fffffffffft
pred4: ft
因此,一个比另一个快得多并不明显,这取决于特定的配置。
反过来做怎么样?对产品进行流处理,并对它们应用谓词。
List<Predicate<Product>> predicates = getPredicates();
List<Product> products = getProducts();
List<Product> filtered = products.stream().filter(product -> {
Iterator<Predicate<Product>> iterator = predicates.iterator();
while (iterator.hasNext()) {
Predicate<Product> currentPredicate = iterator.next();
if (currentPredicate.test(product)) {
iterator.remove();
return true;
}
}
return false;
}).collect(Collectors.toList());
缺点是您必须小心将哪个集合用于谓词,并不总是支持Iterator.remove
。
编辑:看来我读得不够仔细。我认为使用循环时,每种方法各取一个效果最好。
List<Product> products = getProducts();
List<Predicate<Product>> predicates = getPredicates();
List<Product> matchingProducts = new ArrayList<>(predicates.size());
for (Product product : products) {
if (predicates.isEmpty()) {
break;
}
for (int predicateIndex = 0; predicateIndex < predicates.size(); predicateIndex++) {
Predicate<Product> predicate = predicates.get(predicateIndex);
if (predicate.test(product)) {
matchingProducts.add(product);
predicates.remove(predicateIndex);
break;
}
}
}
实际上,设法通过一条流来实现它,并花了时间
,你是对的,本杰明。
List<Predicate<Product>> predicates = getPredicates();
List<Product> products = getProducts();
List<Product> matches = products.stream()
.takeWhile(product -> !predicates.isEmpty())
.filter(product -> {
Iterator<Predicate<Product>> iterator = predicates.iterator();
while (iterator.hasNext()) {
if (iterator.next().test(product)) {
iterator.remove();
return true;
}
}
return false;
})
.collect(Collectors.toList());
只需确保takwhile
在filter
之前,否则会跳过最后一个匹配元素。
我刚刚开始玩Java 8 lambda,我正在尝试实现一些我在函数式语言中习惯的东西。 例如,大多数函数语言都有某种对序列进行操作的find函数,或返回第一个元素的列表,该元素的谓词为。我能看到的在《Java八号》中实现这一点的唯一方法是: 然而,这似乎没有效率,因为过滤器将扫描整个列表,至少在我的理解(这可能是错误的)。有更好的办法吗?
我想要找到合适的正则表达式匹配的行数。输入是通过Java Stream插入的日志文件。我想对这个流应用多个过滤器,但每隔一段时间计算一次。
我陷入了java流操作的边缘案例... 我想对以下行为进行编码:“从一个任意的水果篮子中,收集20个最小的,除了最小的梨,因为我们不想那样。” 额外的奖励:来的篮子可能没有任何梨。 null 我不能使用本地布尔值并在筛选第一个pear后将其设置为,因为lambda中的所有局部变量都必须是final的。 最坏的情况是,我可以将篮子一分为二,梨和非梨,对梨进行排序,如果有的话,适当地将它们子列表。这看
问题内容: 我想要一种惯用的方式来找到与谓词匹配的列表中的第一个元素。 当前代码非常丑陋: 我已经考虑过将其更改为: 但是必须有一些更优雅的方法……如果返回一个值而不是没有找到匹配项引发异常,那将是一个很好的选择。 我知道我可以像这样定义一个函数: 但是,如果已经有内置的插件开始用这样的实用函数填充代码,这是很鸡肋的(人们可能不会注意到它们已经在那里,因此随着时间的推移它们会不断重复出现)。 问题
问题内容: 我想做类似的事情: Python的标准库中是否有类似行为? 我知道在这里自己动手很容易,但是我正在寻找一种更标准的方法。 问题答案: 您可以使用filter方法: 或列表理解: 要查找单个元素,可以尝试: 尽管如果没有匹配项将引发异常,因此您可能希望将其包装在try / catch中。方括号()使之成为生成器表达式,而不是列表理解。 就我个人而言,尽管我只是使用常规的过滤器/理解并采用
使用java stream,我有一个ClassA列表,应用于流以进行过滤,所以使用List。stream()。过滤器(谓词)。这样,谓词就需要ClassA的谓词来应用,但我真的想要String的谓词,因为ClassA。Field1是字符串类型。因此,与其让谓词包含f- 缺少的链接是什么,我需要如何转换流才能做到这一点? 对于其他上下文,在过滤之后,我需要从过滤列表中提取第二个字段,因此目标是拥有C