Pons
Pons

Reputation: 1111

How to replace nested loops with Java 8 streams

I want to use Java 8 stream for the below implementation. Basically i want to parse one list and form another list of different objects.

Input - list of Person pojos, Output - list of PersonInfo pojos

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

    Person max = new Person();
    max.setName("Max");
    max.setAge(10);
    max.addAddress(new Address("Street1", "City1"));
    max.addAddress(new Address("Street2", "City2"));

    Person peter = new Person();
    peter.setName("Peter");
    peter.setAge(20);
    peter.addAddress(new Address("Street1", "City1"));
    peter.addAddress(new Address("Street2", "City2"));

    persons.add(max);
    persons.add(peter);

    System.out.println("Input: " + persons);

    List<PersonInfo> personInfos = new ArrayList<PersonInfo>();
    PersonInfo personInfo = null;
    for (Person person : persons) {
        for (Address addr : person.getCurrAndPrevAddrs()) {
            personInfo = new PersonInfo();
            personInfo.setName(person.getName());
            personInfo.setAge(person.getAge());
            personInfo.setAddrs(addr);              
            personInfos.add(personInfo);
        }
    }

    System.out.println("Output: " + personInfos.toString());

sample output: Input: [Max 10 [Street1 City1, Street2 City2]

, Peter 20 [Street1 City1, Street2 City2]]

Output: [Max 10 Street1 City1

, Max 10 Street2 City2

, Peter 20 Street1 City1

, Peter 20 Street2 City2]

Upvotes: 5

Views: 12795

Answers (4)

Shanank
Shanank

Reputation: 1

A cleaner and elegant way to do this could be :

 List<PersonInfo> personInfos = persons.stream()
                .map(person -> person.getCurrAndPrevAddrs())
                .flatMap(List::stream)
                .map(this::createPersonInfo)
                .collect(Collectors.toList());

 private PersonInfo createPersonInfo() {
        PersonInfo personInfo = new PersonInfo();
        personInfo.setName(person.getName());
        personInfo.setAge(person.getAge());
        personInfo.setAddrs(addr);
        return personInfo;
    }

Upvotes: -1

MikaelF
MikaelF

Reputation: 3664

One way to (1) improve readability and (2) simplify maintenance of your code is to add a toPersonInfo method to your Person class, like so:

public class Person {
    //getters, setters, etc.
    public List<PersonInfo> toPersonInfos() {
        List<PersonInfo> result = new ArrayList<>();
        for (Address addr : getCurrentAndPrevAddrs()) {
            PersonInfo pi = new PersonInfo();
            pi.setName(this::getName);
            pi.setAge(this::getAge);
            pi.setAddrs(this::addr);
            result.add(pi);
        }
        return result;
    }
}

That way, if you ever change your PersonInfo or your Person class, you only have to change one method, and it's right there in your Person class.

It also greatly simplifies the stream operation:

personInfos = persons.stream().flatMap(p -> p.toPersonInfos.stream()).collect(Collectors.toList());

Note that this will not necessarily return an ordered list.

Upvotes: 1

shmosel
shmosel

Reputation: 50776

List<PersonInfo> personInfos = persons.stream().flatMap(person -> person.getCurrAndPrevAddrs().stream().map(addr -> {
        PersonInfo personInfo = new PersonInfo();
        personInfo.setName(person.getName());
        personInfo.setAge(person.getAge());
        personInfo.setAddrs(addr);              
        return personInfo;
})).collect(Collectors.toList());

Upvotes: 5

ninnemannk
ninnemannk

Reputation: 1296

Here is a simplified version of what you're trying to do. I simplified the Pojos for my testing.

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

Person person1 = new Person("person1");
Person person2 = new Person("person2");

persons.add(person1);
persons.add(person2);

List<PersonInfo> personInfos = new ArrayList<PersonInfo>();
persons.stream().forEach(person -> {    
  person.getCurrAndPrevAddrs().stream().forEach(address -> {
    PersonInfo personInfo = new PersonInfo("personInfo");
    personInfo.setAddress(address);
    personInfos.add(personInfo);
  });
});

System.out.println("Output: " + personInfos.toString());

Upvotes: 3

Related Questions