web-dev-qa-db-fra.com

Filtrage de flux pour la meilleure correspondance

Mon but est de filtrer pour une meilleure correspondance. Dans mon exemple, j'ai une liste de personnes que je souhaite filtrer par nom et prénom.

La prescendance correspondante serait:

  1. correspondance du prénom et du prénom, retourne la première correspondance
  2. correspond seulement au nom de famille, retourne la première correspondance
  3. aucun match, jeter une exception

Mon code jusqu'ici:

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

En supposant que Person implémente equals et 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 ..."))
    );
16
Cyril

Vous pouvez utiliser

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

Seuls les éléments portant le nom de famille correct seront pris en compte et le meilleur élément sera renvoyé, à savoir celui dont le prénom correspond. Sinon, le premier élément correspondant est renvoyé.

Comme déjà mentionné dans un commentaire , une boucle for pourrait être plus efficace s'il existe un meilleur élément, car elle peut court-circuiter. S'il n'y a pas de meilleur élément avec le nom et le prénom correspondants, tous les éléments doivent être vérifiés dans toutes les implémentations.

7
Holger

Je proposerais ceci:

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);
2
Ondra K.

Le bon outil est .findFirst(). Vous pouvez également utiliser .limit(1).

0
ncmathsadist