ccznyo
ccznyo

Reputation: 1

Filtering Java Nested List

I've a school list which contains class, class list which also contains student and student are also another list. I want to apply two nested filter which first will check that if any class have a empty student list and second filter is for checking that if school has any empty class list and finally it should return the list but I just can't apply two filters as nested, I keep getting syntax error. I'm a bit new to stream api.

result = result.stream()
          .filter(school -> school.getSchoolClassList().stream()
                    .filter(schoolClass-> schoolClass.getStudentList().stream()
                    .anyMatch(schoolClass-> schoolClass.getStudentList().size() > 0))
          .anyMatch(school -> school.getSchoolClassList().size() > 0))
          .collect(Collectors.toList());

Upvotes: 0

Views: 130

Answers (2)

motaa
motaa

Reputation: 337

I am not sure if I understood you correctly but as far as I got it is that you want to get all schools that either have empty classes or that have classes without students.

What you can do is defining the predicates outside of the stream.

Predicate<School> empty_students_filter = school ->
    school.getSchoolClassList().stream().map(SchoolClass::getStudentList).anyMatch(List::isEmpty);

Predicate<School> empty_classes_filter = school -> school.getSchoolClassList().isEmpty();

Then you can use the predicates inside your filter method and combine them with Predicate.or():

List<School> schools_with_no_or_empty_classes = 
    schools.stream()
           .filter(empty_classes_filter.or(empty_students_filter))
           .collect(Collectors.toList());

Note: if you want to get only the schools that have classes and all classes should have students, then you can adapt the filter as follows with a Predicate.and():

.filter(Predicate.not(empty_classes_filter).and(Predicate.not(empty_students_filter)))

EDIT:

According to your comment, this is not easily doable using the Streams API because you iterate over a Collection of schools and you can only filter schools based on their properties and not filter their properties. So you would need to implement your own custom collector.

I would recommend solving the problem in 2 steps.

Step 1: Remove all classes from a school that contain no students.

Step 2: Stream over and collect all schools that have classes.

//step 1:
result.forEach(school -> {
    List<SchoolClass> school_classes = school.getSchoolClassList();
    List<SchoolClass> empty_classes = 
        school_classes.stream()
                      .filter(school_class -> school_class.getStudentList().isEmpty())
                      .collect(Collectors.toList());
    school.getSchoolClassList().removAll(empty_classes);
});

//step 2:
List<School> remaining_schools = result.stream()
                                       .filter(school -> !school.getSchoolClassList().isEmpty())
                                       .collect(Collectors.toList());

Upvotes: 0

edean
edean

Reputation: 496

You might want to add the resulting Syntax error. However, as I see at first is, that you are using class as an identifier, when it is actually a reserved keyword in Java programming language. Consider renaming the identifiers to something alike schoolClass.

Upvotes: 1

Related Questions