gpt4 book ai didi

java-8 - 改进 Java 8 在 "War and Peace"中查找最常用单词的方法

转载 作者:行者123 更新时间:2023-12-04 16:31:05 25 4
gpt4 key购买 nike

我在 Richard Bird 的书中读到这个问题:在 War and Peace(或任何其他与此相关的文本)中找到前五个最常见的单词。

这是我目前的尝试:

public class WarAndPeace {
public static void main(String[] args) throws Exception {
Map<String, Integer> wc =
Files.lines(Paths.get("/tmp", "/war-and-peace.txt"))
.map(line -> line.replaceAll("\\p{Punct}", ""))
.flatMap(line -> Arrays.stream(line.split("\\s+")))
.filter(word -> word.matches("\\w+"))
.map(s -> s.toLowerCase())
.filter(s -> s.length() >= 2)
.collect(Collectors.toConcurrentMap(
w -> w, w -> 1, Integer::sum));

wc.entrySet()
.stream()
.sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
.limit(5)
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));

}
}

这绝对看起来很有趣并且运行得相当快。在我的笔记本电脑上,它打印以下内容:
$> time java -server -Xmx10g -cp target/classes tmp.WarAndPeace
the: 34566
and: 22152
to: 16716
of: 14987
a: 10521
java -server -Xmx10g -cp target/classes tmp.WarAndPeace 1.86s user 0.13s system 274% cpu 0.724 total

它通常在 2 秒内运行。您能否从表现力和性能的角度对此提出进一步的改进建议?

PS:如果您对这个问题的丰富历史感兴趣,请参阅 here

最佳答案

您正在重新编译每一行和每个单词的所有正则表达式。而不是 .flatMap(line -> Arrays.stream(line.split("\\s+"))).flatMap(Pattern.compile("\\s+")::splitAsStream) . .filter(word -> word.matches("\\w+")) 也一样:使用 .filter(Pattern.compile("^\\w+$").asPredicate()) . map 也一样.

可能最好换.map(s -> s.toLowerCase()).filter(s -> s.length() >= 2)为了不打电话toLowerCase()对于一个字母的单词。

你不应该使用 Collectors.toConcurrentMap(w -> w, w -> 1, Integer::sum) .首先,您的流不是并行的,因此您可以轻松替换 toConcurrentMaptoMap .其次,使用 Collectors.groupingBy(w -> w, Collectors.summingInt(w -> 1)) 可能更有效(尽管需要测试)因为这会减少装箱(但添加一个终结器步骤,将一次装箱所有值)。

而不是 (e1, e2) -> Integer.compare(e2.getValue(), e1.getValue())您可以使用现成的比较器:Map.Entry.comparingByValue() (虽然可能是品味问题)。

总结一下:

Map<String, Integer> wc =
Files.lines(Paths.get("/tmp", "/war-and-peace.txt"))
.map(Pattern.compile("\\p{Punct}")::matcher)
.map(matcher -> matcher.replaceAll(""))
.flatMap(Pattern.compile("\\s+")::splitAsStream)
.filter(Pattern.compile("^\\w+$").asPredicate())
.filter(s -> s.length() >= 2)
.map(s -> s.toLowerCase())
.collect(Collectors.groupingBy(w -> w,
Collectors.summingInt(w -> 1)));

wc.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(5)
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));

如果您不喜欢方法引用(有些人不喜欢),您可以将预编译的正则表达式存储在变量中。

关于java-8 - 改进 Java 8 在 "War and Peace"中查找最常用单词的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35931922/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com