【发布时间】:2026-02-01 17:00:01
【问题描述】:
在使用字谜练习期间,我发现执行后的代码在输出中存在重复,具体取决于 Stream 类中 sorted() 方法的使用时刻。
当我在filter() 和forEach() 方法之前进行排序时
words.stream()
.sorted()
.filter(s1 -> !alreadyFound.contains(s1) && words.stream()
.filter(s2 -> isAnagram.apply(s1, s2))
.count() == maxAnagrams)
.forEach(s1 -> {
它给出了这些结果:
abel able bale bela elba
alger glare lager large regal
angel angle galen glean lange
caret carte cater crate trace
elan lane lean lena neal
evil levi live veil vile
但是当我在filter() 之后和forEach() 方法之前使用sorted() 时
words.stream()
.filter(s1 -> !alreadyFound.contains(s1) && words.stream()
.filter(s2 -> isAnagram.apply(s1, s2))
.count() == maxAnagrams)
.sorted()
然后它给出了这些结果:
abel able bale bela elba
abel able bale bela elba
alger glare lager large regal
angel angle galen glean lange
angel angle galen glean lange
abel able bale bela elba
abel able bale bela elba
caret carte cater crate trace
caret carte cater crate trace
caret carte cater crate trace
caret carte cater crate trace
elan lane lean lena neal
abel able bale bela elba
evil levi live veil vile
angel angle galen glean lange
alger glare lager large regal
angel angle galen glean lange
alger glare lager large regal
elan lane lean lena neal
angel angle galen glean lange
alger glare lager large regal
elan lane lean lena neal
elan lane lean lena neal
evil levi live veil vile
evil levi live veil vile
elan lane lean lena neal
alger glare lager large regal
caret carte cater crate trace
evil levi live veil vile
evil levi live veil vile
似乎在第二种方法中,程序正在复制结果并将已经找到的单词添加到输出中。我想知道为什么会这样?
我正在使用:
jdk1.8.0_201
示例代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main2 {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
List<String> alreadyFound = new ArrayList<>();
BiFunction<String, String, Boolean> isAnagram = (s1, s2) -> {
if (s1.length() != s2.length()) return false;
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
return Arrays.equals(c1, c2);
};
try (InputStream inputStream = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt").openStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
Stream<String> stream = new BufferedReader(inputStreamReader).lines()) {
stream.forEach(words::add);
} catch (IOException e1) {
e1.printStackTrace();
}
long maxAnagrams = Collections.max(words.stream()
.map(s1 -> words.stream()
.filter(s2 -> isAnagram.apply(s1, s2))
.count())
.collect(Collectors.toList())
);
words.stream()
// .sorted()
.filter(s1 -> !alreadyFound.contains(s1) && words.stream()
.filter(s2 -> isAnagram.apply(s1, s2))
.count() == maxAnagrams)
// .sorted()
.forEach(s1 -> {
alreadyFound.add(s1);
words.stream()
.filter(s2 -> isAnagram.apply(s1, s2))
.forEach(s2 -> {
alreadyFound.add(s2);
System.out.print(" " + s2);
});
System.out.println();
});
}
}
// 编辑:题外话 我相信这是达到预期结果的最佳方式:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main4 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try (InputStream inputStream = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt").openStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
Stream<String> stream = new BufferedReader(inputStreamReader).lines()) {
List<List<String>> anagrams = new ArrayList<>(stream
.collect(Collectors.groupingBy(o -> {
char[] chars = o.toCharArray();
Arrays.sort(chars);
return new String(chars);
}))
.values());
int maxAnagrams = anagrams.parallelStream()
.mapToInt(List::size)
.max()
.orElse(0);
anagrams.stream()
.filter(strings -> strings.size() == maxAnagrams)
.sorted(Comparator.comparing(o -> o.get(0)))
.forEach(strings -> {
strings.forEach(s -> System.out.print(s + " "));
System.out.println();
});
} catch (IOException e1) {
e1.printStackTrace();
}
long stop = System.currentTimeMillis();
System.out.println(stop - start);
}
}
【问题讨论】:
-
如果我能正确计算括号,你在流操作中有一个流,我也可以看到 2
System.out。否则你会期待什么? -
如果你将内心的流线分解成它自己的功能,它可能会让你的生活更轻松。我喜欢 BiFunction 的使用,但是如果没有将过滤条件作为谓词,解析起来有点麻烦。
-
我相信你的过滤器中发生了一些事情,如果你先对它进行排序,它会导致它删除重复项 - 但在第二个没有发生的情况下。我正在尝试重新编写它,但我得到了与您看到的相同的重复项。
-
您已经根据流的处理顺序创建了代码;您的过滤谓词假定它可以假定前一个元素已由
forEach处理。这在定义上是被破坏的,正如你所看到的,在某些情况下会在实践中被破坏,比如在使用sorted()或并行流时。此外,您的代码进行重复的线性搜索,即使是冗余的,效率也非常低。通常,您应该重新考虑使用forEach处理所有事情的习惯,从如何将流收集到List开始...... -
感谢所有回复,关于“效率”,我已经为这个问题添加了更好的解决方案:) 关于下面描述的问题,上面介绍的算法对于像
sorted()这样的操作很敏感,它可以遍历流。
标签: java foreach java-stream