Как я могу преобразовать свой код с помощью API потока Java 8? - PullRequest
0 голосов
/ 05 марта 2019

Пишу простой способ распечатать статистику серии результатов игр.В каждой игре есть список результатов, которые содержат перечисления в зависимости от результата игры.Мой инструктор прокомментировал TODO в моем коде:

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) + " %");

}

Я знаком с лямбда-выражениями.Я пытался искать решения в Интернете, но не смог найти примеры потока, обращающегося к полям поля класса.Я был бы рад, если бы вы могли дать мне решение или предоставить мне соответствующее руководство.Спасибо.

Ответы [ 3 ]

0 голосов
/ 05 марта 2019

groupingBy подходит для этого случая:

Map<Outcome, Long> map = games.stream()
        .flatMap(game -> game.getOutcomes().stream())
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

И получите win, lose count:

long win = map.get(Outcomes.WIN);
long lose = map.get(Outcomes.LOSE);
...

Чтобы получить all count, вам нужно сложить всезначения с карты

long all = map.values().stream()
    .mapToLong(Long::valueOf)
    .sum();
0 голосов
/ 05 марта 2019

Вы можете транслировать игры, просматривать карты результатов, а затем собирать их на карту отсчетов:

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();
0 голосов
/ 05 марта 2019

Чтобы получить доступ к полям класса в Stream, используйте map:

games.stream().map(game -> 
  game.getOutcomes().stream().map(outcome -> {
    // do something with each `outcome`
  })
)

В приведенном выше коде предполагается, что getOutcomes() возвращает List, что не указано втекущая версия вопроса OP.

Обратите внимание, что вы не можете просто увеличить счетчики в пределах Stream, как вы, возможно, надеетесь, потому что все переменные, используемые в Stream s, должны быть окончательными или эффективно конечными.Вам нужно будет еще немного покопаться в Stream API, чтобы понять, как увеличить, как вы делали это в исходном решении.

Подсказка: вы хотите сделать что-то вроде this , который использует Collectors.groupingBy () .

...