我必须编写程序,该程序应该是为字谜读取文件并显示单词+他的字谜。 Txt文件非常大,使用扫描仪后,listOfWords的大小为:25000。
输出示例:
word anagram1 anagram2 anagram3 ...
word2 anagram1 anagram2...
我有代码,但它很有效但很慢:
private static List<String> listOfWords = new ArrayList<String>();
private static List<ArrayList<String>> allAnagrams = new ArrayList<ArrayList<String>>();
public static void main(String[] args) throws Exception {
URL url = new URL("www.xxx.pl/textFile.txt");
Scanner scanner = new Scanner(url.openStream());
while (scanner.hasNext()) {
String nextToken = scanner.next();
listOfWords.add(nextToken);
}
scanner.close();
while (listOfWords.isEmpty() == false) {
ArrayList<String> anagramy = new ArrayList<String>();
String wzor = listOfWords.remove(0);
anagramy.add(wzor);
char[] ch = wzor.toCharArray();
Arrays.sort(ch);
for (int i = 0; i < listOfWords.size(); i++) {
String slowo = listOfWords.get(i);
char[] cha = slowo.toCharArray();
Arrays.sort(cha);
if (Arrays.equals(ch, cha)) {
anagramy.add(slowo);
listOfWords.remove(i);
i--;
}
}
allAnagrams.add(anagramy);
}
for (ArrayList<String> ar : allAnagrams) {
String result = "";
if (ar.size() > 1) {
for (int i = 1; i < ar.size(); i++) {
result = ar.get(i) + " ";
}
System.out.println(ar.get(0) + " " + result);
}
}
}
我必须用Java 8编写它 - 流但我不知道。可以使用Streams来读取URL +搜索字谜吗?你可以通过Stream搜索字谜来帮助我吗?老师告诉我,代码应该比我的整个列表更短。只有几行,这可能吗?
答案 0 :(得分:4)
您可以将文件中的单词读入List或直接创建它的流:
try (InputStream is = new URL("http://www.someurl.pl/file.txt").openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Stream<String> stream = reader.lines()) {
//do something with stream
}
然后只是在列表上流式传输并收集字谜,其中所有具有相同排序字符列表的单词都被视为字谜:
Map<String, List<String>> anagrams =
stream.collect(Collectors.groupingBy(w -> sorted(w)));
排序方法只是按照示例中的方式对字母进行排序:
public static String sorted(String word) {
char[] chars = word.toCharArray();
Arrays.sort(chars);
return new String(chars);
}
答案 1 :(得分:4)
让我们创建单独的方法来排序字母。您也可以使用Stream API执行此操作:
private static String canonicalize(String s) {
return Stream.of(s.split("")).sorted().collect(Collectors.joining());
}
现在你可以阅读一些Reader
,从中提取单词并按规范形式对单词进行分组:
Map<String, Set<String>> map = new BufferedReader(reader).lines()
.flatMap(Pattern.compile("\\W+")::splitAsStream)
.collect(Collectors.groupingBy(Anagrams::canonicalize, Collectors.toSet()));
接下来,您可以第三次使用Stream API删除单个字母组:
return map.values().stream().filter(list -> list.size() > 1).collect(Collectors.toList());
现在您可以将一些读者传递给此代码以从中提取字谜。这是完整的代码:
import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.*;
public class Anagrams {
private static String canonicalize(String s) {
return Stream.of(s.split("")).sorted().collect(Collectors.joining());
}
public static List<Set<String>> getAnagrams(Reader reader) {
Map<String, Set<String>> map = new BufferedReader(reader).lines()
.flatMap(Pattern.compile("\\W+")::splitAsStream)
.collect(Collectors.groupingBy(Anagrams::canonicalize, Collectors.toSet()));
return map.values().stream().filter(list -> list.size() > 1).collect(Collectors.toList());
}
public static void main(String[] args) throws IOException {
getAnagrams(new StringReader("abc cab tat aaa\natt tat bbb"))
.forEach(System.out::println);
}
}
打印
[att, tat]
[abc, cab]
如果您想使用网址,只需将StringReader
替换为new InputStreamReader(new URL("www.xxx.pl/textFile.txt").openStream(), StandardCharsets.UTF_8)
如果要提取anagram集的第一个元素,应稍微修改解决方案:
public static Map<String, Set<String>> getAnagrams(Reader reader) {
Map<String, List<String>> map = new BufferedReader(reader).lines()
.flatMap(Pattern.compile("\\W+")::splitAsStream)
.distinct() // remove repeating words
.collect(Collectors.groupingBy(Anagrams::canonicalize));
return map.values().stream()
.filter(list -> list.size() > 1)
.collect(Collectors.toMap(list -> list.get(0),
list -> new TreeSet<>(list.subList(1, list.size()))));
}
这里的结果是地图,其中键是anagram集中的第一个元素(首先出现在输入文件中),值是按字母顺序排序的其余元素(我创建一个子列表来跳过第一个元素,然后移动它们进入TreeSet
进行排序;替代方案是list.stream().skip(1).sorted().collect(Collectors.toList())
)。
使用示例:
getAnagrams(new StringReader("abc cab tat aaa\natt tat bbb\ntta\ncabr\nrbac cab crab cabrc cabr"))
.entrySet().forEach(System.out::println);
答案 2 :(得分:0)
您可以尝试此方法
//---------------Anagram---------------------------------
String w1 = "Triangle".toLowerCase(), w2 = "Integral".toLowerCase();
HashMap<String, Integer> w1Map = new HashMap<String, Integer>();
HashMap<String, Integer> w2Map = new HashMap<String, Integer>();
w1Map = convertToHashMap(w1);
w2Map = convertToHashMap(w2);
if( !(w1.equals(w2)) && (w1Map.keySet().equals(w2Map.keySet())))
System.out.println(w1+" and "+w2+" are anagrams");
else
System.out.println(w1+" and "+w2+" are not anagrams");
在方法下面调用
public static HashMap<String, Integer> convertToHashMap(String s) {
HashMap<String, Integer> wordMap = new HashMap<String, Integer>();
for (int i = 0;i < s.length(); i++){
wordMap.put(String.valueOf(s.charAt(i)), Integer.valueOf(s.charAt(i)));
}
return wordMap;