Java Потоковый фильтр на основе типа набора - PullRequest
0 голосов
/ 31 января 2020

Есть ли способ отфильтровать поле «Набор» в потоке или списке на основе набора с использованием лямбда-потока?

Пример:

    List<Person> persons = new ArrayList<Person>();
    Set<String> hobbySet1 = new HashSet<String>();
    hobbySet1.add("H1");
    hobbySet1.add("H2");
    hobbySet1.add("H3");

    Set<String> hobbySet2 = new HashSet<String>();
    hobbySet2.add("H2");
    hobbySet2.add("H4");

    Set<String> hobbySet3 = new HashSet<String>();
    hobbySet3.add("H3");

    Set<String> hobbySet4 = new HashSet<String>();
    hobbySet4.add("H4");

    persons.add(new Person("P1", hobbySet1));
    persons.add(new Person("P2", hobbySet2));
    persons.add(new Person("P3", hobbySet3));
    persons.add(new Person("P4", hobbySet4));

    Set<String> searchHobby = new HashSet<String>();
    searchHobby.add("H1");
    searchHobby.add("H3");

Я хочу отфильтровать хобби из списка «Лица» основанный на searchHobby, так что будут сохраняться только те лица, чьи хобби указаны в searchHobby.

Я знаю, как этого добиться с помощью простого для l oop.

    List<Person> result = new ArrayList<Person>();

    for (String sHobby : searchHobby) {
        for (Person p : persons) {
            Set<String> pHobbySet = p.getHobbies();
            for (String pHobby : pHobbySet) {
                if (pHobby.equalsIgnoreCase(sHobby)) {
                    Optional<Person> wasAdded = result.stream().filter(s->s.getName()==p.getName()).findAny();
                    if(wasAdded.isEmpty()) {
                        result.add(p);
                        break;
                    }
                }
            }
        }
    }

Я ищу решение java Stream Filter.


PS Person

public class Person {
    String name;
    Set<String> hobbies;

    public Person(String name, Set<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    public String getName(){
        return name;
    }

    public Set<String> getHobbies(){
        return hobbies;
    }
}

Ответы [ 4 ]

4 голосов
/ 31 января 2020

anyMatch вернет true, если какое-либо хобби соответствует.

List<Person> personsWithHobby = persons.stream()
    .filter(person -> person.getHobbies().stream()
            .anyMatch(searchHobby::contains))
    .collect(Collectors.toList());
1 голос
/ 31 января 2020

Вы можете попробовать:

persons.stream()
    .filter(p -> p.getHobbies().stream()
            .filter(searchHobby::contains)
            .findAny().isPresent()
    )
    .collect(Collectors.toList());
1 голос
/ 31 января 2020

Вы можете использовать метод containsAll , чтобы найти человека, который увлекается хобом searchHobby:

List<Person> collect = persons.stream()
            .filter(person -> person.getHobbies().containsAll(searchHobby))
            .collect(Collectors.toList());

Или если вам нужно найти людей, в которых хотя бы один человек увлекается searchHobbies тогда вы можете использовать removeAll :

List<Person> collect = persons.stream()
            .filter(person -> new HashSet<>(person.getHobbies()).removeAll(searchHobby))
            .collect(Collectors.toList());
0 голосов
/ 31 января 2020

Циклы for обрабатывают условия немного неловко, неоптимально. Простое решение было бы:

List<Person> result = persons.stream()
       .filter(p -> hasHobby(p.getHobbies(), searchHobby))
       .collect(Collectors.toList());

boolean hasHobby(Set<String> personHobbies, Set<String> searchHobbies) {
    Set<String> pH = personHobbiers.stream()
            .map(String::toLowerCase).collect(Collectors.toSet());
    Set<String> sH = searchHobbiers.stream()
            .map(String::toLowerCase).collect(Collectors.toSet());
    return !pH.retainAll(sh).isEmpty();
}

Это тоже неоптимально. Особенно жаль, что нужен случай игнорирования. И просто пересечение трудно. Однако с парой хобби это не должно быть трудно. В начале можно прописать строчные буквы searchHobbies.

...