我已经实现了一些代码来查找txt sample.txt
文件中的anagrams字,并在控制台上输出它们。 txt文档在每行中都包含String(word)。
如果我想在txt.file中找到带有百万或二十亿字的字谜词,那么这是正确的使用方法吗?如果不是在这种情况下我应该使用哪种技术?
我感谢任何帮助。
示例
abac
aabc
hddgfs
fjhfhr
abca
rtup
iptu
xyz
oifj
zyx
toeiut
yxz
jrgtoi
oupt
abac aabc abca
xyz zyx yxz
代码
package org.reader;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
// To store the anagram words
static List<String> match = new ArrayList<String>();
// Flag to check whether the checkWorld1InMatch() was invoked.
static boolean flagCheckWord1InMatch;
public static void main(String[] args) {
String fileName = "G:\\test\\sample2.txt";
StringBuilder sb = new StringBuilder();
// In case of matching, this flag is used to append the first word to
// the StringBuilder once.
boolean flag = true;
BufferedReader br = null;
try {
// convert the data in the sample.txt file to list
List<String> list = Files.readAllLines(Paths.get(fileName));
for (int i = 0; i < list.size(); i++) {
flagCheckWord1InMatch = true;
String word1 = list.get(i);
for (int j = i + 1; j < list.size(); j++) {
String word2 = list.get(j);
boolean isExist = false;
if (match != null && !match.isEmpty() && flagCheckWord1InMatch) {
isExist = checkWord1InMatch(word1);
}
if (isExist) {
// A word with the same characters was checked before
// and there is no need to check it again. Therefore, we
// jump to the next word in the list.
// flagCheckWord1InMatch = true;
break;
} else {
boolean result = isAnagram(word1, word2);
if (result) {
if (flag) {
sb.append(word1 + " ");
flag = false;
}
sb.append(word2 + " ");
}
if (j == list.size() - 1 && sb != null && !sb.toString().isEmpty()) {
match.add(sb.toString().trim());
sb.setLength(0);
flag = true;
}
}
}
}
} catch (
IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
for (String item : match) {
System.out.println(item);
}
// System.out.println("Sihwail");
}
private static boolean checkWord1InMatch(String word1) {
flagCheckWord1InMatch = false;
boolean isAvailable = false;
for (String item : match) {
String[] content = item.split(" ");
for (String word : content) {
if (word1.equals(word)) {
isAvailable = true;
break;
}
}
}
return isAvailable;
}
public static boolean isAnagram(String firstWord, String secondWord) {
char[] word1 = firstWord.toCharArray();
char[] word2 = secondWord.toCharArray();
Arrays.sort(word1);
Arrays.sort(word2);
return Arrays.equals(word1, word2);
}
}
答案 0 :(得分:6)
对于200亿字,你将无法将所有这些字体保存在RAM中,因此您需要一种方法来处理它们。
20,000,000,000字。 Java需要相当多的内存来存储字符串,因此每个字符可以计算2个字节,并且开销至少为38个字节。
这意味着一个字符的20,000,000,000个单词需要800,000,000,000字节或800 GB,这比我所知道的任何计算机都要多。
您的文件将包含少于20,000,000,000个不同的单词,因此如果您只存储一次单词(例如Set
),则可以避免内存问题。
答案 1 :(得分:3)
首先是较小的数字。
由于最好使用更强大的数据结构,不要读取核心中的所有行,而是按行读取。
Map<String, Set<String>> mapSortedToWords = new HashMap<>();
Path path = Paths.get(fileName);
try (BufferedReader in = Files.newBufferedReader(Path, StandardCharsets.UTF_8)) {
for (;;) {
String word = in.readLine();
if (word == null) {
break;
}
String key = sorted(word);
Set<String> words = mapSortedToWords.get(key);
if (words == null) {
words = new TreeSet<String>();
mapSortedToWords.put(key, words);
}
words.add(word);
}
}
for (Set<String> anagrams : mapSortedToWords.values()) {
if (anagrams.size() > 1) {
... anagrams
}
}
static String sorted(String word) {
char[] letters = word.toCharArray();
Arrays.sort(letters);
return new String(letters);
}
这会在地图中存储一组单词。与abac aabc abca
相比。
对于大量存储(sortedLetters,word)的数据库会更好。像Derby或H2这样的嵌入式数据库不会造成安装问题。
答案 2 :(得分:2)
对于您指定的文件大小类型(200亿字),显然您的代码存在两个主要问题,
Shape line = ws.Shapes.AddLine(98, 60, 432, 60);
line.Line.ForeColor.RGB = Color.Red.ToArgb();
AND
List<String> list = Files.readAllLines(Paths.get(fileName));
程序中的这两行基本上都是问题,
对于大多数系统,上述两个问题的答案都是否定的。
所以你的目标是减少内存占用量并减少迭代次数。
因此,您需要按块读取文件块,并使用某种搜索数据结构(如Trie )来存储您的单词。
对于上述两个主题,您会在SO上找到许多问题,例如
Fastest way to incrementally read a large file
Finding anagrams for a given word
上面的算法说明你必须先为你的单词创建一个字典。
无论如何,我相信你没有现成的答案。拿一个十亿字的文件(这本身就是一项非常困难的任务),看看哪些有效,哪些无效但你的当前代码显然不起作用。
希望它有所帮助!!
答案 3 :(得分:0)
更新
您可以使用地图查找下面的字谜。对于您拥有的每个单词,您可以对其字符进行排序并获取已排序的字符串。所以,这将是你的字谜地图的关键。而这个键的价值将是其他字谜词。
public void findAnagrams(String[] yourWords) {
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
for (String word : yourWords) {
String sortedWord = sortedString(word);
List<String> values = anagrams.get(sortedWord);
if (values == null)
values = new LinkedList<>();
values.add(word);
anagrams.put(sortedWord, values);
}
System.out.println(anagrams);
}
private static String sortedString(String originalWord) {
char[] chars = originalWord.toCharArray();
Arrays.sort(chars);
String sorted = new String(chars);
return sorted;
}
答案 4 :(得分:0)
使用流来读取文件。这样你只能同时存储一个单词。
FileReader file = new FileReader("file.txt"); //filestream
String word;
while(file.ready()) //return true if there a bytes left in the stream
{
char c = file.read(); //reads one character
if(c != '\n')
{
word+=c;
}
else {
process(word); // do whatever you want
word = "";
}
}