Reputation: 809
I've got a List<String>
which represents the ID's (can be duplicate), of items from another list, which is a List<Cheat>
, where each Cheat has a String ID and a List<Integer> RNG
. Both have accessor methods in Cheat.
I need to convert this list of ID's, into a list of RNG's for each Cheat that I have been supplied with the ID for.
For example, I could have 3 Cheats:
1:{ID:1, RNG:{1,2,3}}
2:{ID:2, RNG{1,2}}
3:{ID:3, RNG:{1}}
And a List of ID's of:
{3,1,1,2}.
I would need to end up with a final list of {1,1,2,3,1,2,3,1,2}, which is the RNG's of Cheat 3, then the RNG's of cheat 1, then the RNG's of cheat 1 again, then finally the RNG's of cheat 2.
If anyone could help me out it would be appreciated. Thank you.
I've tried and failed with:
ImmutableList<Integer> sequenceRngs = cheatIds.stream()
.map(s -> cheats.stream()
.filter(cheat -> cheat.getId().equals(s))
.findFirst()
.map(cheat -> cheat.getRng()))
.flatMap(cheat -> cheat.getRng())
.collect(ListUtils.toImmutableList());
Upvotes: 0
Views: 144
Reputation: 31878
You can attain that with the following steps:
Create a map of cheatId
to RNG id
s associated:
Map<Integer, List<Integer>> map = cheats.stream()
.collect(Collectors.toMap(Cheat::getId,
cheat -> cheat.getRng().stream().map(RNG::getId).collect(Collectors.toList())));
Iterate over the cheatIds
provided as input and get the corresponding RNG ids from the map to collect as output:
List<Integer> output = cheatIds.stream()
.flatMap(ch -> map.get(ch).stream())
.collect(Collectors.toList());
Upvotes: 0
Reputation: 645
One possible solution:
import java.util.List;
import java.util.stream.Collectors;
class Scratch {
static class Cheat {
int id;
List<Integer> rng;
public Cheat(int id, List<Integer> rng) {
this.id = id;
this.rng = rng;
}
}
public static void main(String[] args) {
List<Cheat> allCheats = List.of(
new Cheat(1, List.of(1,2,3)),
new Cheat(2, List.of(1,2)),
new Cheat(3, List.of(1))
);
List<Integer> result = List.of(3, 1, 1, 2).stream()
.flatMap(id -> allCheats.stream()
.filter(cheat -> cheat.id == id)
.findFirst().orElseThrow().rng.stream())
.collect(Collectors.toList());
System.out.println(result);
}
}
The key is to use flatMap to get the result in a single - not nested - Collection in the end.
Upvotes: 2
Reputation: 7810
The lambda that you pass to flatMap
should return a Stream
, not a List
. And you should handle the case where there's no such element in the stream - even if you are sure there is. Something like this should do:
final ImmutableList<String> sequenceRngs = cheatIds.stream().flatMap(id ->
cheats.stream().filter(cheat -> id.equals(cheat.getId()))
.findAny().orElseThrow(IllegalStateException::new)
.getRng().stream())
.collect(ListUtils.toImmutableList());
Also, I would propose to convert the list of cheats to a map - that would simplify the code and reduce the complexity of searching from O(n) to O(1).
Upvotes: 1