我想知道.NET是否提供了通过列表或字典对象进行前缀搜索的任何标准功能。我偶然发现了StringDictionary
,但无法弄清楚它是否能为我做到这一点。
如果它可以进行前缀搜索,它是否也能进行子串搜索或让我使用正则表达式进行搜索?
提前致谢。
答案 0 :(得分:5)
StringDictionary
只是一个哈希表,其中键和值为string
s。这在泛型之前存在(当Dictionary<string, string>
不可能时)。
此处所需的数据结构为trie。 CodeProject上有实现:
或者,如果你是那种人,请自己动手(见CLRS)。
答案 1 :(得分:4)
我不相信StringDictionary支持前缀搜索,但是如果你使用SortedList<,>
,你可以在键的范围内进行二进制搜索,直到找到前缀之前和之后的第一个条目。
答案 2 :(得分:2)
我认为StringDictionary
是旧学校(pre-generics)。您可能应该使用Dictionary(Of String, String)
,因为它实现了IEnumerable(想想LINQ)。一个非常lame thing about StringDictionary是它不区分大小写。
答案 3 :(得分:0)
我对此here进行了通用实现。
由于string
实现了IEnumerable<char>
,因此您可以将char
用作TKeyElement
的参数。
答案 4 :(得分:0)
以下是一组字符串的基本实现,可以通过前缀有效地搜索这些字符串。
这个想法是将集合中的所有单词保留在一个特里,当查询找到所有以某个前缀开头的单词时,我们找到与该前缀中最后一个字符相对应的节点,然后从DFS中找到该节点收集并返回其所有后代。
public class PrefixSearchableSet
{
private readonly Dictionary<char, TrieNode> _letterToNode = new Dictionary<char, TrieNode>();
private bool _isEmptyWordIncluded;
public PrefixSearchableSet(IEnumerable<string> words = null)
{
if (words is null) return;
foreach (string word in words)
{
AddWord(word);
}
}
public void AddWord(string word)
{
if (word is null) return;
if (word is "") _isEmptyWordIncluded = true;
else
{
TrieNode node = FindOrAdd(_letterToNode, word[0]);
foreach (char c in word.Skip(1))
{
node = FindOrAdd(node.Children, c);
}
node.Word = word;
}
}
public List<string> GetWords(string prefix)
{
List<string> words = new List<string>();
if (prefix is null) return words;
if (prefix is "")
{
if (_isEmptyWordIncluded) words.Add("");
foreach (TrieNode trieNode in _letterToNode.Values)
{
trieNode.CollectWords(words);
}
return words;
}
_letterToNode.TryGetValue(prefix[0], out TrieNode node);
foreach (char c in prefix.Skip(1))
{
if (node is null) break;
node.Children.TryGetValue(c, out node);
}
node?.CollectWords(words);
return words;
}
private static TrieNode FindOrAdd(Dictionary<char, TrieNode> letterToNode, char key)
{
if (letterToNode.TryGetValue(key, out TrieNode node)) return node;
return letterToNode[key] = new TrieNode();
}
private class TrieNode
{
public Dictionary<char, TrieNode> Children { get; } = new Dictionary<char, TrieNode>();
public string Word { get; set; }
public void CollectWords(List<string> words)
{
if (Word != null) words.Add(Word);
foreach (TrieNode child in Children.Values)
{
child.CollectWords(words);
}
}
}
}