// Copyright 2009 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.android.stardroid.search; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Given a set of strings such as search terms, this class allows you to search * for that string by prefix. * @author John Taylor * */ public class PrefixStore { static private class TrieNode { Map<Character, TrieNode> children = new HashMap<>(); // we need to store the originals to support insensitive case searching Set<String> results = new HashSet<>(); } private TrieNode root = new TrieNode(); private static final Set<String> EMPTY_SET = Collections.unmodifiableSet(new HashSet<String>()); /** * Search for any queries matching this prefix. Note that the prefix is * case-independent. * * TODO(@tcao) refactor this API. Search should return a relevance ranked list. */ public Set<String> queryByPrefix(String prefix) { prefix = prefix.toLowerCase(); TrieNode n = root; for (int i = 0; i < prefix.length(); i++) { TrieNode c = n.children.get(prefix.charAt(i)); if (c == null) { return EMPTY_SET; } n = c; } Set<String> coll = new HashSet<String>(); collect(n, coll); return coll; } private void collect(TrieNode n, Collection<String> coll) { coll.addAll(n.results); for (Character ch : n.children.keySet()) { collect(n.children.get(ch), coll); } } /** * Put a new string in the store. */ public void add(String string) { TrieNode n = root; String lower = string.toLowerCase(); for (int i = 0; i < lower.length(); i++) { TrieNode c = n.children.get(lower.charAt(i)); if (c == null) { c = new TrieNode(); n.children.put(lower.charAt(i), c); } n = c; } n.results.add(string); } /** * Put a whole load of objects in the store at once. * @param strings a collection of strings. */ public void addAll(Collection<String> strings) { for (String string : strings) { add(string); } } }