Reputation: 165
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
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
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