java 中的索引书
Indexing book in java
我正在尝试编写一个程序,将文本文件作为输入,在其中添加单词作为键,并且与单词相关联的值应该是它们所在的页码。文本如下所示:
Page1
blah bla bl
Page2
some blah
所以对于单词 "blah" 输出必须是
blah : [1,2].
我只插入了键,但不知道如何向它们插入关联值。这是我目前拥有的:
BufferedReader reader = new BufferedReader(input);
try {
Map <String, List<Integer>> library
= new TreeMap<String, List<Integer>>();
String line = reader.readLine();
while (line != null) {
String[] tokens = line.trim().split("\s+");
for (int i = 0; i < tokens.length; i++) {
String word = tokens[i];
if (!library.containsKey(word)
&& !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
List<Integer> pages = library.get(word);
int page = getNum(tokens[0]);
pages.add(page);
page++;
}
}
}
}
line = reader.readLine();
}
}
要获取页数,我使用此方法
private static int getNum(String s) {
int result = 0;
int p = 1;
int i = s.length() - 1;
while (i >= 0) {
int d = s.charAt(i) - '0';
if (d >= 0 && d <= 9) {
result += d * p;
} else {
break;
}
i--;
p *= 10;
}
return result;
}
感谢您的所有想法!
你应该尝试这样的事情。我不完全确定你是如何使用这些页面的,但这段代码将检查图书馆是否包含这个词(就像你已经拥有的那样),如果不包含,它会将页码添加到该词的列表中。
if (!library.containsKey(word) && !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
}
else {
library.put(word, library.get(word).add(page));
}
pages
变量在内部 if
语句的范围内声明。一旦该块结束,变量就超出范围并且未定义。如果您想稍后使用页面列表,则需要将其声明为 class 变量。
我假设您稍后使用 pages
生成 table 内容。但这并不是绝对必要的,因为您可以稍后从您的单词索引中生成它 - 我将在下面演示如何做到这一点。
您还需要声明一个 currentPage
变量来保存您看到的最新 'PageN' 文本。无需手动增加:您只需将数字存储在文本中(处理空白页)。
页码似乎总是在他们自己的行上,因此页面检测应该在行文本上而不是在单词上(这处理了一行读取 'for more information see Page72' 的情况)。
检查第一个词前是否有有效的页码也是值得的。
因此,将所有这些放在一起,您的代码的结构应该类似于以下内容:
Map<String, Set<Integer>> index = new TreeMap<>();
int currentPage = -1;
String currentLine;
while ((currentLine = reader.readLine()) != null) {
if (isPage(currentLine)) {
currentPage = getPageNum(currentLine);
} else {
assert currentPage > 0;
for (String word: words(currentLine)) {
if (!index.contains(word))
index.put(word, new TreeSet<>());
index.get(word).add(currentPage);
}
}
}
我已将方法 words
、isPage
和 getPageNum
分开,但您似乎拥有所有这些方法的工作代码。
我还将页面列表更改为集合,以反映您只需要在索引中引用一次单词页面这一事实。
要从索引中获取所有页面的有序列表,请使用:
index.values().stream()
.flatMap(List::stream).distinct().sorted()
.collect(Collectors.toList());
这是假设 Java8,但如果您没有流,转换起来并不难。
如果您要生成反向索引(页面到单词),那么出于效率原因,您应该在处理单词时创建反向映射 (Map<Integer, List<String>>
)。
你的问题好像出在这段逻辑上:
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
很明显,您仅在行以 Page 开头时才添加页码,否则 if 条件中的逻辑未执行,因此您从未更新任何单词的页码。
我正在尝试编写一个程序,将文本文件作为输入,在其中添加单词作为键,并且与单词相关联的值应该是它们所在的页码。文本如下所示:
Page1
blah bla bl
Page2
some blah
所以对于单词 "blah" 输出必须是
blah : [1,2].
我只插入了键,但不知道如何向它们插入关联值。这是我目前拥有的:
BufferedReader reader = new BufferedReader(input);
try {
Map <String, List<Integer>> library
= new TreeMap<String, List<Integer>>();
String line = reader.readLine();
while (line != null) {
String[] tokens = line.trim().split("\s+");
for (int i = 0; i < tokens.length; i++) {
String word = tokens[i];
if (!library.containsKey(word)
&& !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
List<Integer> pages = library.get(word);
int page = getNum(tokens[0]);
pages.add(page);
page++;
}
}
}
}
line = reader.readLine();
}
}
要获取页数,我使用此方法
private static int getNum(String s) {
int result = 0;
int p = 1;
int i = s.length() - 1;
while (i >= 0) {
int d = s.charAt(i) - '0';
if (d >= 0 && d <= 9) {
result += d * p;
} else {
break;
}
i--;
p *= 10;
}
return result;
}
感谢您的所有想法!
你应该尝试这样的事情。我不完全确定你是如何使用这些页面的,但这段代码将检查图书馆是否包含这个词(就像你已经拥有的那样),如果不包含,它会将页码添加到该词的列表中。
if (!library.containsKey(word) && !word.startsWith("Page")) {
library.put(word, new LinkedList<Integer>());
}
else {
library.put(word, library.get(word).add(page));
}
pages
变量在内部 if
语句的范围内声明。一旦该块结束,变量就超出范围并且未定义。如果您想稍后使用页面列表,则需要将其声明为 class 变量。
我假设您稍后使用 pages
生成 table 内容。但这并不是绝对必要的,因为您可以稍后从您的单词索引中生成它 - 我将在下面演示如何做到这一点。
您还需要声明一个 currentPage
变量来保存您看到的最新 'PageN' 文本。无需手动增加:您只需将数字存储在文本中(处理空白页)。
页码似乎总是在他们自己的行上,因此页面检测应该在行文本上而不是在单词上(这处理了一行读取 'for more information see Page72' 的情况)。
检查第一个词前是否有有效的页码也是值得的。
因此,将所有这些放在一起,您的代码的结构应该类似于以下内容:
Map<String, Set<Integer>> index = new TreeMap<>();
int currentPage = -1;
String currentLine;
while ((currentLine = reader.readLine()) != null) {
if (isPage(currentLine)) {
currentPage = getPageNum(currentLine);
} else {
assert currentPage > 0;
for (String word: words(currentLine)) {
if (!index.contains(word))
index.put(word, new TreeSet<>());
index.get(word).add(currentPage);
}
}
}
我已将方法 words
、isPage
和 getPageNum
分开,但您似乎拥有所有这些方法的工作代码。
我还将页面列表更改为集合,以反映您只需要在索引中引用一次单词页面这一事实。
要从索引中获取所有页面的有序列表,请使用:
index.values().stream()
.flatMap(List::stream).distinct().sorted()
.collect(Collectors.toList());
这是假设 Java8,但如果您没有流,转换起来并不难。
如果您要生成反向索引(页面到单词),那么出于效率原因,您应该在处理单词时创建反向映射 (Map<Integer, List<String>>
)。
你的问题好像出在这段逻辑上:
if (tokens[0].startsWith("Page")
&& library.containsKey(word)) {
很明显,您仅在行以 Page 开头时才添加页码,否则 if 条件中的逻辑未执行,因此您从未更新任何单词的页码。