显示有限流中所有最长的单词

min*_*ibi 2 java java-8 java-stream

我必须使用Streams API从给定文件中找到所有最长的单词.我做了它在几个步骤,但寻找一些"一个班轮",其实我处理整个文件两次,第一次找字和第二的最大长度为所有比较的最大长度,假设它不是最​​好的表现; P有人能帮帮我吗?看看代码:

public class Test {
    public static void main(String[] args) throws IOException {
        List<String> words = Files.readAllLines(Paths.get("alice.txt"));
        OptionalInt longestWordLength = words.stream().mapToInt(String::length).max();
        Map<Integer, List<String>> groupedByLength = words.stream().collect(Collectors.groupingBy(String::length));
        List<String> result = groupedByLength.get(longestWordLength.getAsInt());
    }
}
Run Code Online (Sandbox Code Playgroud)

我想直截了当:

List<String> words = Files.readAllLines(Paths.get("alice.txt"));
List<String> result = // code
Run Code Online (Sandbox Code Playgroud)

文件每行只包含一个单词,无论如何它并不重要 - 问题是关于正确的流代码.

Mur*_*nik 6

您可以将单词从长度收集到单词中,而不是仅保留最大长度,然后将最长的单词收集起来:

List<String> longestWords =
    Files.lines(Paths.get("alice.txt"))
         .collect(Collectors.groupingBy(String::length))
         .entrySet()
         .stream()
         .sorted(Map.Entry.<Integer, List<String>> comparingByKey().reversed())
         .map(Map.Entry::getValue)
         .findFirst()
         .orElse(null);
Run Code Online (Sandbox Code Playgroud)

编辑:
正如Malte Hartwig所指出的那样,max在流式地图上使用更加优雅(并且可能更快):

List<String> longestWords =
    Files.lines(Paths.get("alice.txt"))
         .collect(Collectors.groupingBy(String::length))
         .entrySet()
         .stream()
         .max(Map.Entry.comparingByKey())
         .map(Map.Entry::getValue)
         .orElse(null);
Run Code Online (Sandbox Code Playgroud)

编辑2:
上述两种解决方案都存在内置的低效率,因为它们都构建了一个映射,基本上存储了文件中所有字符串的长度而不是最长的字符串.如果性能比用例中的优雅更重要,那么您可以自己编写,Collector以保留列表中最长的字符串:

private static int stringInListLength(List<String> list) {
    return list.stream().map(String::length).findFirst().orElse(0);
}

List<String> longestWords =
    Files.lines(Paths.get("alice.txt"))
         .collect(Collector.of(
             LinkedList::new,
             (List<String> list, String string) -> {
                 int stringLen = string.length();
                 int listStringLen = stringInListLength(list);
                 if (stringLen > listStringLen) {
                     list.clear();
                 }
                 if (stringLen >= listStringLen) {
                     list.add(string);
                 }
             },
             (list1, list2) -> {
                 int list1StringLen = stringInListLength(list1);
                 int list2StringLen = stringInListLength(list2);
                 if (list1StringLen > list2StringLen) {
                     return list1;
                 }
                 if (list2StringLen > list1StringLen) {
                     return list2;
                 }
                 list1.addAll(list2);
                 return list1;
             }
         ));
Run Code Online (Sandbox Code Playgroud)

  • `stringInListLength`可以实现为`list.isEmpty()?0:list.get(0).length()`...此外,[this](/sf/answers/2053737451/)可能是一个很好的阅读. (3认同)
  • @minizibi你可以通过使用`Stream.max(Comparator)`而不是`sorted().findFirst()`:`... entrySet().stream().max来更容易阅读(imo). Map.Entry.comparingByKey()).图(Map.Entry的::的getValue).orElse(空)`.这样可以节省一条线,更简单(没有反向调用)和更快(我想最大速度要快于排序,因为它不需要那么多的比较). (2认同)