我有一组我想要搜索的字符串,只提供前几个字符。
例如,考虑字符串列表:[tom,tomaz,alice,tolstoy,john]。字符串[to]将导致列表[tom,tomaz,tolstoy]。
效果是一个主要问题,列表可能非常大。
优化此功能的最佳方法是什么?指标?排序?怎么样?
谢谢!
答案 0 :(得分:2)
trie是通用的解决方案,正如已经建议的那样,但是如果你想要一个没有外部依赖关系的轻量级且相对快速的解决方案,只需将所有字符串放入TreeSet
并使用tailSet()
即可找到与前缀匹配的第一个元素,然后遍历尾部集,直到找到不匹配的字符串。 (注意:如果你的字符串都不匹配前缀,这甚至可能是第一个元素。)
如果你的列表不超过几千个字符串,这种方法在实践中已经足够了。
答案 1 :(得分:1)
如果您坚持使用列表,则您的选项有限。它根本不适合这种事情。
完全符合您要求的数据结构称为Trie (Wikipedia Entry)
快速谷歌提出杜克大学的这个java实现: http://www.cs.duke.edu/~ola/courses/cps108/fall96/joggle/trie/Trie.java
答案 2 :(得分:0)
看看Solr和Lucene。他们通过索引进行字符串搜索,或者您可以像其他人建议的那样编写自己的字符串。
答案 3 :(得分:0)
如果像这样的搜索是优先事项,我建议调查tries来安排您的数据,并且不会导致与您的其他要求冲突。
答案 4 :(得分:0)
假设您的列表足够小以便保留在内存中,我会使用trie。
这将为您提供与前缀长度成比例的查找时间。
答案 5 :(得分:0)
如果您想在内存中完全执行此操作并且没有任何依赖关系,这里有一个快速选项:
static int MAX_PREFIX = 3;
Map<String, List<String>> map = new HashMap<String, List<String>>();
public void addItem(String item) {
for (int i = 0; i < MAX_PREFIX && i < item.length(); i++) {
String prefix = item.substring(0, i);
List<String> matches = map.get(prefix);
if (matches == null) {
matches = new ArrayList<String>();
map.put(prefix, matches);
}
matches.add(item);
}
}
public List<String> getMatches(String prefix) {
List<String> matches = map.get(prefix);
return matches == null ? Collections.<String>emptyList() : matches;
}
这是非常快的,因为它只是一次Map
次查询,从您的前缀String
直接转换为所需结果的List<String>
。如果你的列表太大而不适合内存那么你需要考虑去外部。如前所述,您可能希望查看Lucene的本地索引。或者数据库,只需索引列并执行LIKE 'prefix%'
查询。