Search code examples
listlambdajava-8flatmap

Working with Inner List containing Item with specific Property value, Java 8


I created a code, for specific task. But, I think: must to have better manner to do this code.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class InnerListContainingItemWithSpecificPropertyValue {

  public static void main(String[] args) {

    List<List<Person>> nestedPersonList = Arrays.asList(
        Arrays.asList(new Person("a0", 0), new Person("b0", 1)), //0
        Arrays.asList(new Person("a1", 0), new Person("b1", 1)), //1
        Arrays.asList(new Person("a2", 0), new Person("b2", 1)), //2
        Arrays.asList(new Person("a3", 0), new Person("b3", 1)) // 5
    );

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

    nestedPersonList.stream().flatMap(List::stream).forEach(outerPerson -> {

      //Determine if Exist Some inner List
      boolean ageFound = outNestedPersonList
          .stream()
          .flatMap(List::stream)
          .filter(innerPerson -> outerPerson.getAge() == innerPerson.getAge())
          .count() > 0L;

      List<Person> listPersonWithAge;
      if (!ageFound) {
        listPersonWithAge = new ArrayList<>();
        outNestedPersonList.add(listPersonWithAge);
      } else {
        // Get the Inner List with Specific Property Value
        listPersonWithAge = outNestedPersonList
            .stream()
            .filter(innerListPerson -> {
              return innerListPerson
                  .stream()
                  .filter(innerPerson -> outerPerson.getAge() == innerPerson.getAge())
                  .count() > 0L;
            }).findFirst().get();

      }
      listPersonWithAge.add(outerPerson);
      // Do something
      if (listPersonWithAge.size() == 4) {
        System.out.println("listPerson with age:" + outerPerson.getAge() + "\twill be removed!");
        outNestedPersonList.remove(listPersonWithAge);
      }

    });

  }

  public static class Person {

    private String name;
    private int age;

    public Person(String name, int age) {
      this.name = name;
      this.age = age;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public int getAge() {
      return age;
    }

    public void setAge(int age) {
      this.age = age;
    }

    @Override
    public int hashCode() {
      int hash = 5;
      hash = 73 * hash + Objects.hashCode(this.name);
      hash = 73 * hash + this.age;
      return hash;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (getClass() != obj.getClass()) {
        return false;
      }
      final Person other = (Person) obj;
      if (this.age != other.age) {
        return false;
      }
      if (!Objects.equals(this.name, other.name)) {
        return false;
      }
      return true;
    }

    @Override
    public String toString() {
      return "Person{" + "name=" + name + ", age=" + age + '}';
    }

  }

}

output:

listPerson with age:0   will be removed!
listPerson with age:1   will be removed!

Alternatively my code:

  1. How know if is there inner List containing some item with some Property Value?
  2. How I can to obtain the inner list with that item?
  3. If the external list does not contain an internal list, How create one?

Solution

  • The first step of improving your code is to avoid using flatMap. It makes it easier to operate on the nested data, but you are trying to operate on one of the sublists, not on the all of the people as a whole.

    You are trying to operate on one sublist, not all of the people in all of the lists, so instead of using flatMap, you can nest two sets of stream operations.

    listOfListOfPeople.stream()
        // filter out sublists that don't have anyone with the target age
        .filter(sublist ->
            // Check if the nested list contains anyone with the given age
            sublist.stream().anyMatch(p -> p.age == targetAge))
        // get one sublist out of the stream
        .findAny()
        // if there wasn't one, get an empty list
        .orElse(Collections.emptyList());
    

    If you want to be able to modify the empty list you get if there aren't any people with the target age, replace the last line with something like .orElseGet(ArrayList::new).