Java 8 Streams - 如何比较元素?
Java 8 Streams - how to compare elements?
我想使用 Java 流在 .txt
文件中查找字谜。这是我拥有的:
try (InputStream is = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt").openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Stream<String> stream = reader.lines()) {
以及字谜的方法:
public boolean isAnagram(String firstWord, String secondWord) {
char[] word1 = firstWord.replaceAll("[\s]", "").toCharArray();
char[] word2 = secondWord.replaceAll("[\s]", "").toCharArray();
Arrays.sort(word1);
Arrays.sort(word2);
return Arrays.equals(word1, word2);
}
如何使用 Java 8 Stream 检查 unixdict.txt 中的单词是否为 anagram?有什么方法可以将一个词与流中的所有词进行比较吗?
我认为您最好的选择可能是使用 multimap 收集器将流转换为 Guava multimap
,使用字符串的排序版本作为映射的键。有关如何执行此操作的示例,请参阅 Cleanest way to create a guava MultiMap from a java8 stream。如果您只想要生成的字谜集,则可以使用
multimap.asMap().entrySet().stream()...
根据您的需要过滤和收集结果。
这行得通。我首先在流中完成了所有排序,但这样效率更高。
InputStream is = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt")
.openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String word = "germany";
final String sword = sortedWord(word);
reader.lines().filter(w -> sortedWord(w).compareTo(sword) == 0).forEach(
System.out::println);
static String sortedWord(String w) {
char[] chs = w.toCharArray();
Arrays.sort(chs);
return String.valueOf(chs);
}
一个可能的改进是先过滤单词的长度。你可能想试试这个 word list 因为它有更多的字。
当你想找到所有的变位词时,不建议尝试将一个词与所有其他词进行比较,因为你最终会把每个词与其他词进行比较,这就是所谓的二次time complexity.处理 1,000 个单词,需要进行 100 万次比较,处理 100,000 个单词,需要进行 10,000,000,000 次比较,依此类推。
您可以更改 isAnagram
方法,为 HashMap
:
等数据结构提供查找键
static CharBuffer getAnagramKey(String s) {
char[] word1 = s.replaceAll("[\s]", "").toCharArray();
Arrays.sort(word1);
return CharBuffer.wrap(word1);
}
class CharBuffer
包装了一个 char[]
数组并提供了必要的 equals
和 hashCode
方法而不复制数组内容,这使其更可取构建一个新的 String
.
作为旁注,.replaceAll("[\s]", "")
可以简化为 .replaceAll("\s", "")
,两者都会消除所有 space 个字符,但您问题的示例输入没有 space字符在所有。要删除所有非单词字符,例如撇号和符号,您可以使用 s.replaceAll("\W", "")
.
然后,您可以像
这样在单个线性过程中处理所有单词以查找变位词
URL srcURL = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt");
try(InputStream is = srcURL.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Stream<String> stream = reader.lines()) {
stream.collect(Collectors.groupingBy(s -> getAnagramKey(s)))
.values().stream()
.filter(l -> l.size() > 1)
.forEach(System.out::println);
}
使用此解决方案,对于较大的单词列表,打印可能会成为更昂贵的部分。所以你可能会改变流的操作,例如以下打印出前十名的字谜组合:
stream.collect(Collectors.groupingBy(s -> getAnagramKey(s)))
.values().stream()
.filter(l -> l.size() > 1)
.sorted(Collections.reverseOrder(Comparator.comparingInt(List::size)))
.limit(10)
.forEach(System.out::println);
我想使用 Java 流在 .txt
文件中查找字谜。这是我拥有的:
try (InputStream is = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt").openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Stream<String> stream = reader.lines()) {
以及字谜的方法:
public boolean isAnagram(String firstWord, String secondWord) {
char[] word1 = firstWord.replaceAll("[\s]", "").toCharArray();
char[] word2 = secondWord.replaceAll("[\s]", "").toCharArray();
Arrays.sort(word1);
Arrays.sort(word2);
return Arrays.equals(word1, word2);
}
如何使用 Java 8 Stream 检查 unixdict.txt 中的单词是否为 anagram?有什么方法可以将一个词与流中的所有词进行比较吗?
我认为您最好的选择可能是使用 multimap 收集器将流转换为 Guava multimap
,使用字符串的排序版本作为映射的键。有关如何执行此操作的示例,请参阅 Cleanest way to create a guava MultiMap from a java8 stream。如果您只想要生成的字谜集,则可以使用
multimap.asMap().entrySet().stream()...
根据您的需要过滤和收集结果。
这行得通。我首先在流中完成了所有排序,但这样效率更高。
InputStream is = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt")
.openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String word = "germany";
final String sword = sortedWord(word);
reader.lines().filter(w -> sortedWord(w).compareTo(sword) == 0).forEach(
System.out::println);
static String sortedWord(String w) {
char[] chs = w.toCharArray();
Arrays.sort(chs);
return String.valueOf(chs);
}
一个可能的改进是先过滤单词的长度。你可能想试试这个 word list 因为它有更多的字。
当你想找到所有的变位词时,不建议尝试将一个词与所有其他词进行比较,因为你最终会把每个词与其他词进行比较,这就是所谓的二次time complexity.处理 1,000 个单词,需要进行 100 万次比较,处理 100,000 个单词,需要进行 10,000,000,000 次比较,依此类推。
您可以更改 isAnagram
方法,为 HashMap
:
static CharBuffer getAnagramKey(String s) {
char[] word1 = s.replaceAll("[\s]", "").toCharArray();
Arrays.sort(word1);
return CharBuffer.wrap(word1);
}
class CharBuffer
包装了一个 char[]
数组并提供了必要的 equals
和 hashCode
方法而不复制数组内容,这使其更可取构建一个新的 String
.
作为旁注,.replaceAll("[\s]", "")
可以简化为 .replaceAll("\s", "")
,两者都会消除所有 space 个字符,但您问题的示例输入没有 space字符在所有。要删除所有非单词字符,例如撇号和符号,您可以使用 s.replaceAll("\W", "")
.
然后,您可以像
这样在单个线性过程中处理所有单词以查找变位词URL srcURL = new URL("http://wiki.puzzlers.org/pub/wordlists/unixdict.txt");
try(InputStream is = srcURL.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Stream<String> stream = reader.lines()) {
stream.collect(Collectors.groupingBy(s -> getAnagramKey(s)))
.values().stream()
.filter(l -> l.size() > 1)
.forEach(System.out::println);
}
使用此解决方案,对于较大的单词列表,打印可能会成为更昂贵的部分。所以你可能会改变流的操作,例如以下打印出前十名的字谜组合:
stream.collect(Collectors.groupingBy(s -> getAnagramKey(s)))
.values().stream()
.filter(l -> l.size() > 1)
.sorted(Collections.reverseOrder(Comparator.comparingInt(List::size)))
.limit(10)
.forEach(System.out::println);