Как получить среднюю длину слов с помощью выражения Lambda

У меня есть текстовый файл списка слов, я хочу получить минимальные, максимальные и средние длины слов из этого файла.

У меня есть метод потока:

public static Stream<String> readWords(String filename) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        Stream<String> stringStream = reader.lines();
        return stringStream;
    } catch (IOException exn) {
        return Stream.<String>empty();
    }
}

В моем основном методе тестирования я печатаю max и min

System.out.println(readWords(filename)
        .min(Comparator.comparing(s -> s.length()))
        .get()
        .length()
);
System.out.println(readWords(filename)
        .max(Comparator.comparing(s -> s.length()))
        .get()
        .length()
);

работает как ожидалось.

Вопросы:
Можно ли получить среднее значение длины слова, как в минуту и ​​макс? В обоих случаях да или нет, как это сделать (только как выражение Лямбды)?

Ответ 1

Метод lines() даст вам поток строк, а не слова. Когда у вас есть Stream, вызовите flatMap, чтобы заменить строки словами, предоставив выражение лямбда для разделения слов:

Stream<String> stringStream = reader.lines().flatMap( line -> 
    Stream.of(line.split("\\s+"))
);

Это исправит вашу реализацию max и min. Это также влияет на правильность любого среднего расчета, который вы хотите реализовать.

Чтобы получить среднее значение, вы можете вызвать mapToInt, чтобы сопоставить поток слов с их длиной (с результатом IntStream), затем вызовите average, который возвращает OptionalDouble.

System.out.println(readWords(filename)
    .mapToInt( s -> s.length() )  // or .mapToInt(String::length)
    .average()
    .getAsDouble());

Ответ 2

Используйте IntSummaryStatistics, чтобы получить минимальное, максимальное и среднее за один проход.

IntSummaryStatistics summary = readWords(filename)
    .collect(Collectors.summarizingInt(String::length));
System.out.format("min = %d, max = %d, average = %.2f%n",
    summary.getMin(), summary.getMax(), summary.getAverage());

Ответ 3

На основе официальной документации о сокращения

System.out.println(readWords(filename)
                .mapToInt(String::length)
                .average()
                .getAsDouble()
);

Обратите внимание, что вы можете и, вероятно, должны использовать ссылки на методы, такие как String::length