FedericoAlvarez
FedericoAlvarez

Reputation: 165

Passing objects through streams and flatmaps

I'm dealing with Java 8 streams and I wondering if I could resolve this problem in a fancy way.

That's my scenario: Suppose I have a list of parties and inside each element I have the names of the members. I want to iterate over the list and make a new one with the names and which party they belong to.

My first approach was:

@Test
public void test(){

    Party firstParties = new Party("firstParty",Lists.newArrayList("Member 1","Member 2","Member 3"));
    Party secondParty = new Party("secondParty",Lists.newArrayList("Member 4","Member 5","Member 6"));

    List<Party> listOfParties = Lists.newArrayList();
    listOfParties.add(firstParty);
    listOfParties.add(secondParty);

    List<Elector> electors = new ArrayList<>();
    listOfParties.stream().forEach(party ->
        party.getMembers().forEach(memberName ->
            electors.add(new Elector(memberName,party.name))
        )
    );

}

class Party {
    List<String> members = Lists.newArrayList();
    String name = "";

    public Party(String name, List<String> members) {
        this.members = members;
        this.name = name;
    }

    public List<String> getMembers() {
        return members;
    }
}

class Elector{

    public Elector(String electorName,String partyName) {

    }

}

In my second approach I tried to use maps an flatmap's operations:

@Test
public void test(){

    Party firstParty = new Party("firstParty",Lists.newArrayList("Member 1","Member 2","Member 3"));
    Party secondParty = new Party("secondParty",Lists.newArrayList("Member 4","Member 5","Member 6"));

    List<Party> listOfParties = Lists.newArrayList();
    listOfParties.add(firstParty);
    listOfParties.add(secondParty);

    List<Elector> people = listOfParties.stream().map(party -> party.getMembers())
            .flatMap(members -> members.stream())
            .map(membersName -> new Elector(membersName, party.name)) #Here is my problem variable map doesn't exist
            .collect(Collectors.toList());

}

The problem is I can't access to the party object inside the map operation. So the question again is Can I do in a more functional way? (like the second approach)

Thanks!

Upvotes: 6

Views: 2942

Answers (2)

flakes
flakes

Reputation: 23684

To keep everything readable I would add a helper method in the Party class (or a static method somewhere else) to get a Stream<Elector>:

public Stream<Elector> electors() {
    return getMembers().stream().map(member -> new Elector(member, name));
}
// Alternatively
public static Stream<Elector> electors(final Party p) {
    return p.getMembers().stream().map(member -> new Elector(member, p.name));
}

And then just use that in your flatmap

final List<Elector> people = listOfParties.stream()
    .flatMap(Party::electors)
    .collect(Collectors.toList());

Upvotes: 3

Holger
Holger

Reputation: 298599

You decomposed too much into individual operations:

List<Elector> people = listOfParties.stream()
    .flatMap(party -> party.getMembers().stream()
        .map(membersName -> new Elector(membersName, party.name)))
    .collect(Collectors.toList());

This works by moving both map steps into the flatMap step, where only the second one survives, now being applied to the returned “substream”. As pointed out in the comments of your question, you need some kind of Pair type to map the “substream” elements to, but your Elector type fulfills exactly that, as it is constructed using the two values you are interested in. So there is no need to map to a generic Pair(member,party) just to map to Elector afterwards.

Upvotes: 11

Related Questions