【问题标题】:How to get words average length using Lambda Expression如何使用 Lambda 表达式获取单词的平均长度
【发布时间】:2015-09-11 23:33:16
【问题描述】:

我有一个单词列表文本文件,我想从该文件中获取最小、最大和平均单词长度。

我有一个流方法:

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();
    }
}

在我的主要测试方法中,我打印的是最大值和最小值

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()
);

它按预期工作。

问题:
是否有可能像我在 min 和 max 中所做的那样获得单词长度的平均值?无论是或否,如何做到这一点(仅作为 Lambda 表达式)?

【问题讨论】:

  • 您可以使用 .reduce(0, (i, c) -> c+i.length()) 并将其除以行数。
  • 提示:如果您的文件很大并且有很多行,请使用 collect 而不是 reduce
  • @JoshuaK 感谢您的贡献,我在下面找到了答案

标签: java lambda java-8 java-stream


【解决方案1】:

lines() 方法将为您提供行流,而不是单词。获得 Stream 后,调用 flatMap 将行替换为单词,提供 lambda 表达式来拆分单词:

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

这将更正您对maxmin 的实现。它还会影响您希望实现的任何平均计算的正确性。

要获得平均值,您可以调用mapToInt 将单词流映射到它们的长度(产生IntStream),然后调用average,它返回一个OptionalDouble

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

【讨论】:

  • 效果很好,我喜欢您对 .flatMap 等的意见。
  • @bayou.io 是的,summaryStatistics() 可以。它将返回一个IntSummaryStatistics,给出平均值和更多:计数、总和、最小值和最大值。
  • 不要为一行的单词创建一个临时数组。使用flatMap(Pattern.compile("\\s+")::splitAsStream)。而且您无需手动处理BufferedReader。见Files.lines()
  • @Holger 听起来很有趣,我会试试的。
【解决方案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】:

    基于reductions的官方文档

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

    请注意,您可以并且可能应该使用方法引用,例如 String::length

    【讨论】:

    • 你的代码运行起来太棒了,因为 Stream 输入,我选择了另一个答案,你的答案也是有效的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多