我必须使用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());
}
}
我希望直截了当:
List<String> words = Files.readAllLines(Paths.get("alice.txt"));
List<String> result = // code
文件每行只包含一个单词,无论如何它并不重要 - 问题是关于正确的流代码。
答案 0 :(得分: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);
修改:
强>
正如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);
<强> EDIT2:
强>
在上述两种解决方案中都存在内置的低效率,因为它们都构建了一个映射,基本上存储了文件中全部字符串的长度而不是最长的字符串。如果性能比使用中的优雅更重要,您可以编写自己的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;
}
));
答案 1 :(得分:3)
reduce
会帮助您:
Optional<String> longest = words.stream()
.reduce((s1, s2) -> {
if (s1.length() > s2.length())
return s1;
else
return s2;
});
如果Stream
为空,则会返回Optional.empty
如果您想要所有具有最大长度的单词列表,这件作品将对您有所帮助:
Optional<List<String>> longest = words.stream()
.collect(Collectors.groupingBy(
String::length,
Collectors.toList()
))
.entrySet()
.stream()
.reduce(
(entry1, entry2) -> {
if (entry1.getKey() > entry2.getKey())
return entry1;
else
return entry2;
}
)
.map(Map.Entry::getValue);
答案 2 :(得分:0)
遍历地图键以找到最长的字长