sala sala - 5 months ago 16
Java Question

Stream and filter for structure of Lists

Trying to get list of items from structure and avoid lot of for cycles and ifs, so I wanna use

Stream


For example, lets have a following structure:

class House {
List<Family> familyList;
}

class Family {
List<Person> personList;
String someInfo;

}

class Person {
String name;
int age;
List<Item> itemList;
}

class Item{
String name;
}


I want to create:


  1. List<Item>
    from families

  2. List<Item>
    from families filtered by name

  3. List
    from house, which contain only records filtered by
    Item`name



so far I tried the following:


  1. List testItems = house1.familyList.stream().flatMap(f -> f.personList.stream().flatMap(p ->p.itemList.stream()))
    .collect(Collectors.toList());
    List testItems = house1.familyList.stream().flatMap(f -> f.personList.stream()).flatMap(p->p.itemList.stream())
    .collect(Collectors.toList());

  2. List testItemsFiltered= house1.familyList.stream().flatMap(f -> f.personList.stream().flatMap(p ->p.itemList.stream().filter(item->item.name.equals("Hammer"))))
    .collect(Collectors.toList());



but both are throwing nullpointers

for 3. variant I have no idea so far

kevin edit:

check: familiList contains few
Item
with names - "item1","item2","item3"

List<Family> filteredFamilies = house1.familyList.stream()
.filter(f -> f.personList.stream()
.anyMatch(p ->p.itemList.stream()
.anyMatch(i -> i.name.equals("item1"))))
.collect(Collectors.toList());

for (Family family : filteredFamilies) {
for (Person p : family.personList) {
for (Item i : p.itemList) {
System.out.println(i.name);
}
}
}


results:

item1
item2
item2
item3
item1
item2
item2
item3


befor filtering:

f1-

_p1- it1,it2

_p2- it2,it3,it4

f2

_p3- it1,i2

_p4 i3

f3

_p5 i5

after filter:

f1-

p1- it1

f2

p3- it1

Answer

I tried the first code:

List<Item> testItems = house1.familyList.stream()
               .flatMap(f -> f.personList.stream()
                   .flatMap(p ->p.itemList.stream()))
               .collect(Collectors.toList());

and this code works. It seems that you don't initialize the lists at the beginning. So i would suggest to init them in the constructor and the NullPointer should disappear. Also when the lists are empty no NullPointer appears.

This code should return each family which has a person with a specific item:

String expectedItem = "test";
List<Family> families = house1.familyList.stream()
                .filter(f -> f.personList.stream()
                        .anyMatch(p ->p.itemList.stream()
                                .anyMatch(i -> i.name.equals(expectedItem))))
                .collect(Collectors.toList());

According to the question the answer has also be changed:

String expectedItem = "test";
List<Family> families = house1.familyList.stream()
                .filter(f -> f.personList.stream()
                        .anyMatch(p ->p.itemList.stream()
                                .allMatch(i -> i.name.equals(expectedItem))))
                .collect(Collectors.toList());