在我目前正在进行的计划中,有一部分需要花费一些时间。基本上,我有一个字符串列表和一个目标短语。例如,假设目标短语是“成品库存”。现在,在过滤掉停用词(of)之后,我想从列表中提取包含三个词之一的所有字符串:“inventory”,“finished”和“goods”。现在,我实现了如下想法:
String[] targetWords; // contains "inventory", "finished", and "goods"
ArrayList<String> extractedStrings = new ArrayList<String>();
for (int i = 0; i < listOfWords.size(); i++) {
String[] words = listOfWords.get(i).split(" ");
outerloop:
for (int j = 0; j < words.length; j++) {
for (int k = 0; k < targetWords.length; k++) {
if (words[j].equalsIgnoreCase(targetWords[k])) {
extractedStrings.add(listOfWords.get(i));
break outerloop;
}
}
}
}
该列表包含超过100k个单词,使用这个单词,每个目标短语完成任务需要花费0.4到.8秒。事情是,我有很多这些目标短语需要处理,秒数真的加起来。因此,我想知道是否有人知道更有效的方法来完成这项任务?感谢您的帮助!
答案 0 :(得分:6)
您的100k字列表可以添加(一次)到HashSet。使用wordSet.contains()
- 而不是遍历列表 - HashSet为此提供了恒定时间性能,因此不受列表大小的影响。
答案 1 :(得分:2)
你可以把你的巨大单词列表添加到哈希映射中,然后当你的短语出现时,只需循环你的短语中的单词并检查哈希映射。目前,您正在进行线性搜索,我建议将其缩减为恒定时间搜索。
关键是尽量减少查询。使用这种技术,您可以有效地索引您的巨型单词列表,以便快速查找。
答案 2 :(得分:1)
如果你想要整个短语或者只是listOfWords中的单个单词,我会感到有点困惑。如果你试图从listOfWords获取字符串,如果你的一个目标词在字符串中,这应该适合你。
String[] targetWords= new String[]{"inventory", "finished", "goods"};
List<String> listOfWords = new ArrayList<String>();
// build lookup map
Map<String, ArrayList<String>> lookupMap = new HashMap<String, ArrayList<String>>();
for(String words : listOfWords) {
for(String word : words.split(" ")) {
if(lookupMap.get(word) == null) lookupMap.put(word, new ArrayList<String>());
lookupMap.get(word).add(words);
}
}
// find phrases
Set<String> extractedStrings = new HashSet<String>();
for(String target : targetWords) {
if(lookupMap.containsKey(target)) extractedStrings.addAll(lookupMap.get(target));
}
答案 3 :(得分:1)
您正在通过targetWords
中的每个元素,而不是同时检查来自targetWords的所有单词。此外,您在每次迭代中拆分单词列表而不需要它,从而产生开销。
我建议您将targetWords
合并为一个(已编译)regular expression:
(?xi) # turn on comments, use case insensitive matching
\b # word boundary, i.e. start/end of string, whitespace
( # begin of group containing 'inventory' or 'finished' or 'goods'
inventory|finished|goods # bar separates alternatives
) # end of group
\b # word boundary
不要忘记在正则表达式字符串中双引号退格。
import java.util.regex.*;
...
Pattern targetPattern = Pattern.compile("(?xi)\\b(inventory|finished|goods)\\b");
for (String singleString : listOfWords) {
if (targetPattern.matcher(singleString).find()) {
extractedStrings.add(singleString);
}
}
如果您对正则表达式的速度不满意 - 尽管常规表达式引擎通常针对性能进行了优化 - 您需要进行自己的高速多字符串搜索。 Aho–Corasick string matching algorithm已针对在文本中搜索多个固定字符串进行了优化,但当然,与仅创建模式相比,实现此算法相当费力。
答案 4 :(得分:0)
我会尝试使用ExecutorService
来实现它,以并行搜索每个单词。
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
例如,固定线程池大小:
Executors.newFixedThreadPool(20);