简体   繁体   English

流过滤以获得最佳匹配

[英]Stream filtering for best match

My aim is to filter for a best match. 我的目标是过滤最佳匹配。 In my example I have a list of persons, which I want to filter by surname and firstname. 在我的例子中,我有一个人员列表,我想按姓氏和名字过滤。

The matching prescendence would be: 匹配的优势将是:

  1. both surname and firstname match, return first match 姓氏和名字匹配,返回第一场比赛
  2. only surname matches, return first match 只有姓氏匹配,返回第一场比赛
  3. none match, throw some exception 没有比赛,抛出一些例外

My code so far: 我的代码到目前为止:

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")).???

Assuming Person implements equals and hashCode: 假设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 ..."))
    );

You can use 您可以使用

Person person = persons.stream()
        .filter(p -> p.getSurName().equals("Doe"))
        .max(Comparator.comparing(p -> p.getFirstName().equals("Jane")))
        .orElse(null);

It will only consider elements having the right surname and return the best element of them, which is the one with a matching first name. 它只会考虑具有正确姓氏的元素并返回它们的最佳元素,即具有匹配名字的元素。 Otherwise, the first matching element is returned. 否则,返回第一个匹配元素。

As already mentioned in a comment , a for loop could be more efficient if there is a best element, as it can short circuit. 正如在评论中已经提到的 ,如果存在最佳元素,则for循环可以更有效,因为它可以短路。 If there is no best element with matching surname and first name, all element have to be checked in all implementations. 如果没有匹配姓氏和名字的最佳元素,则必须在所有实现中检查所有元素。

I would propose this: 我建议这个:

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);

The right tool is .findFirst() . 正确的工具是.findFirst() You can also use .limit(1) . 你也可以使用.limit(1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM