Java 流过滤实现最佳匹配
我的目标是筛选出最佳匹配。在我的示例中,我有一个人员列表,我想按姓氏和名字对其进行筛选 匹配的预相关性为:Java 流过滤实现最佳匹配,java,java-8,java-stream,Java,Java 8,Java Stream,我的目标是筛选出最佳匹配。在我的示例中,我有一个人员列表,我想按姓氏和名字对其进行筛选 匹配的预相关性为: 姓氏和名字都匹配,返回第一个匹配 仅姓氏匹配,返回第一个匹配 无匹配,抛出一些异常 到目前为止,我的代码是: final List<Person> persons = Arrays.asList( new Person("Doe", "John"), new Person("Doe", "Jane"), new Person("Munster", "Herman")
final List<Person> persons = Arrays.asList(
new Person("Doe", "John"),
new Person("Doe", "Jane"),
new Person("Munster", "Herman");
Person person = persons.stream().filter(p -> p.getSurname().equals("Doe")).???
final List persons=Arrays.asList(
新人(“Doe”、“John”),
新人(“Doe”、“Jane”),
新人(“蒙斯特”、“赫尔曼”);
Person-Person=persons.stream().filter(p->p.getnames().equals(“Doe”)。???
正确的工具是.findFirst()
。您也可以使用.limit(1)
假设Person实现了equals和hashCode:
Person personToFind = new Person("Doe", "Jane");
Person person = persons.stream()
.filter(p -> p.equals(personToFind))
.findFirst()
.orElseGet(() ->
persons.stream()
.filter(p -> p.getSurname().equals(personToFind.getSurname()))
.findFirst()
.orElseThrow(() -> new RuntimeException("Could not find person ..."))
);
我建议:
Optional<Person> bestMatch = persons.stream()
.filter(p -> "Doe".equals(p.getSurname()))
.reduce((person, person2) -> {
if ("John".equals(person.getFirstName())) {
return person;
} else if ("John".equals(person2.getFirstName())) {
return person2;
}
return person;
});
Person result = bestMatch.orElseThrow(IllegalArgumentException::new);
可选最佳匹配=persons.stream()
.filter(p->“Doe”.equals(p.getnam姓氏()))
.减少((人,人2)->{
if(“John.equals(person.getFirstName())){
返回人;
}else如果(“John”.equals(person2.getFirstName())){
返回人员2;
}
返回人;
});
Person result=bestMatch.orelsetrow(IllegalArgumentException::new);
您可以使用
Person person = persons.stream()
.filter(p -> p.getSurName().equals("Doe"))
.max(Comparator.comparing(p -> p.getFirstName().equals("Jane")))
.orElse(null);
只考虑具有正确姓氏的元素并返回它们的最佳元素,即匹配名称的第一个元素。否则,返回第一个匹配元素。
正如,如果有一个最佳元素,那么
for
循环可能会更有效,因为它可能会短路。如果没有具有匹配姓氏和名字的最佳元素,则必须在所有实现中检查所有元素。假设没有,只需将p->p.equals(personToFind)
与p->p.get姓氏().equals进行交换即可(personofind.getnames())和&p.getFirstName().equals(personofind.getFirstName())
+必要时检查是否为空。@qwerty1423,它将不匹配/满足只有姓氏相等的第二个条件。请再次阅读问题。@GCP它将像处理equals一样工作(假设equals检查我上面写的确切条件)。第二个条件在内部流中被选中。没有更改。您不需要大括号和返回语句。您可以使用表达式lambda。我已经为您编辑了它:)@Eugene:如果存在精确匹配,则此解决方案已经达到最小值。如果没有,则不可避免地至少处理一次所有元素。根据匹配的可能性,您可以重点避免重复元素两次。您不需要if(“John”.equals(person.getFirstName())){
对吗?因为它将被最终的返回者覆盖;
anyway@OndraK.我也想到了类似的事情,问题是这不是短路,你需要遍历整个流源,即使你的结果可能从第一个元素就知道是的,谢谢,你们两个都是正确的。解决方案西里尔提出的效率更高,因为它实际上是短路,另一方面,使用嵌套流,这是某种程度上不可读的。您可以考虑<代码> Studio。使用一个比较器,它对两个名字的匹配率高于仅对姓氏的匹配率,反过来又高于根本不匹配率。您可能希望首先过滤掉最后一个类别。有趣的是,使用一个简单的for
循环,或者甚至是一个for
循环,对按姓氏过滤的人进行过滤,可以生成更简单的nd最大效率的代码。我最初的想法是,像你一样,先按姓氏过滤,然后返回第一个按名字匹配的…或者如果有名字匹配,则只返回第一个;但是似乎没有办法缩短“reduce”操作(不抛出,这将是非惯用的)试着想想,我想出的界面无论如何都会很笨重。这是一个有趣的方法。稳定性呢?如果有两个或两个以上的人都姓Doe
,并且没有一个叫Jane
,那么这是否总是返回相同的人
?@Federicoperalthaffner:它也会返回,如果至少有一个匹配的姓氏,则为第一个完全匹配;如果没有完全匹配,则为第一个姓氏匹配的人。当然,这种行为有点不明确,另请参见…Hmmmm…根据提供的比较器,这对多个max元素很好(如果有多个Jane Doe并且流已排序,则将返回第一个)。但如果没有Janes,它恐怕会返回最后一个Doe。@Federicoperaltachaffner:注意,这个比较器只比较布尔值值;所有名字匹配的人都被认为是彼此平等的,所有名字不匹配的人都被认为是彼此平等的。因此,如果没有名字,matches,将返回第一个“相等”姓氏匹配项。