Reputation: 147
I am writing a simple method to print out statistics of a series of outcomes of games. Every Game has a list of Outcomes in it, which contain enums according to the outcome of a game. My instructor has commented a TODO in my code:
public static void printStatistics(List<Game> games) {
float win = 0;
float lose = 0;
float draw = 0;
float all = 0;
//TODO: should be implemented /w stream API
for (Game g : games) {
for (Outcome o : g.getOutcomes()) {
if (o.equals(Outcome.WIN)) {
win++;
all++;
} else if (o.equals(Outcome.LOSE)) {
lose++;
all++;
} else {
draw++;
all++;
}
}
}
DecimalFormat statFormat = new DecimalFormat("##.##");
System.out.println("Statistics: The team won: " + statFormat.format(win * 100 / all) + " %, lost " + statFormat.format(lose * 100 / all)
+ " %, draw: " + statFormat.format(draw * 100 / all) + " %");
}
I am familiar with lambda expressions. I tried looking online for solutions, but could not find examples of a stream accessing fields of a field of a class. I would be happy if you could give me a solution, or provide me with a relevant tutorial. Thanks.
Upvotes: 3
Views: 99
Reputation: 50776
You can stream games, flatMap to outcomes, then collect them to a map of counts:
Map<Outcome, Long> counts = games.stream()
.map(Game::getOutcomes)
.flatMap(Collection::stream)
.collecting(Collectors.groupingBy(o -> o, Collectors.counting()));
long win = counts.getOrDefault(Outcome.WIN, 0L);
long lose = counts.getOrDefault(Outcome.LOSE, 0L);
long draw = counts.getOrDefault(Outcome.DRAW, 0L);
long all = games.stream()
.mapToInt(g -> g.getOutcomes().size())
.sum();
Upvotes: 5
Reputation: 6300
groupingBy
fits this case:
Map<Outcome, Long> map = games.stream()
.flatMap(game -> game.getOutcomes().stream())
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
And get win
, lose
count:
long win = map.get(Outcomes.WIN);
long lose = map.get(Outcomes.LOSE);
...
To get all
count you need to sum all values from map
long all = map.values().stream()
.mapToLong(Long::valueOf)
.sum();
Upvotes: 2
Reputation: 1445
To access the fields of the class in a Stream
, use map
:
games.stream().map(game ->
game.getOutcomes().stream().map(outcome -> {
// do something with each `outcome`
})
)
The above code assumes that getOutcomes()
returns a List
, which is not specified in the current version of OP's question.
Note that you cannot simply increment counters within a Stream
, as you might hope to, because all variables used within Stream
s must be final or effectively final. You'll have to dig a bit more into the Stream
API to figure out how to increment the way you did in your original solution.
Hint: you want to do something like this, which utilises Collectors.groupingBy().
Upvotes: 0