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)
文件每行只包含一个单词,无论如何它并不重要 - 问题是关于正确的流代码.
您可以将单词从长度收集到单词中,而不是仅保留最大长度,然后将最长的单词收集起来:
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)