Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i transform my code using java 8 stream API?

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.

like image 471
Mangos Avatar asked Apr 25 '26 12:04

Mangos


2 Answers

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();
like image 84
shmosel Avatar answered Apr 28 '26 02:04

shmosel


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();
like image 33
Ruslan Avatar answered Apr 28 '26 01:04

Ruslan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!