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,将返回第一个“相等”姓氏匹配项。