C# 使用.NET StringDictionary在列表/字典中搜索前缀?
我想知道.NET是否提供了通过列表或字典对象进行前缀搜索的标准功能。我偶然发现了C# 使用.NET StringDictionary在列表/字典中搜索前缀?,c#,string,search,prefix,C#,String,Search,Prefix,我想知道.NET是否提供了通过列表或字典对象进行前缀搜索的标准功能。我偶然发现了StringDictionary,但不知道它是否能帮我做到这一点 如果它可以做前缀搜索,它也可以做子字符串搜索,或者让我用正则表达式之类的东西来搜索 提前感谢。我认为StringDictionary不支持前缀搜索,但是如果使用SortedList可以在键的范围内进行二进制搜索,直到找到前缀前后的第一个条目。我认为StringDictionary是一个老派(预泛型)。您可能应该使用字典(字符串,字符串),因为它实现了I
StringDictionary
,但不知道它是否能帮我做到这一点
如果它可以做前缀搜索,它也可以做子字符串搜索,或者让我用正则表达式之类的东西来搜索
提前感谢。我认为StringDictionary不支持前缀搜索,但是如果使用
SortedList
可以在键的范围内进行二进制搜索,直到找到前缀前后的第一个条目。我认为StringDictionary
是一个老派(预泛型)。您可能应该使用字典(字符串,字符串)
,因为它实现了IEnumerable(想想LINQ)。一个极端的问题是它不区分大小写。StringDictionary
只是一个哈希表,其中键和值是string
s。这在泛型之前就存在了(当字典不可能时)
这里需要的数据结构是一个。有以下方面的实现:
或者,如果你是那种人,那就自己动手吧(请参见)。我为这一点提供了一个通用的实现
由于string
实现了IEnumerable
,因此您可以将它与char
一起用作TKeyElement
的参数。下面是一组字符串的基本实现,可以通过前缀进行有效搜索
其思想是将集合中的所有单词保留在一个trie中,当查询以查找以某个前缀开头的所有单词时,我们会找到前缀中最后一个字符对应的节点,然后在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);
}
}
}
}
公共类PrefixSearchableSet
{
专用只读词典_letttonode=新词典();
私人住宅不包括在内;
公共PrefixSearchableSet(IEnumerable words=null)
{
如果(文字为空)返回;
foreach(单词中的字符串)
{
AddWord(word);
}
}
公共无效添加字(字符串字)
{
如果(字为空)返回;
如果(单词为“”)\u ismptywordincluded=true;
其他的
{
三节点节点=FindOrAdd(_letttonode,word[0]);
foreach(word.Skip(1)中的字符c)
{
node=findorad(node.Children,c);
}
node.Word=Word;
}
}
公共列表GetWords(字符串前缀)
{
列表单词=新列表();
如果(前缀为空)返回单词;
if(前缀为“”)
{
如果(_ismptywordinclude)字,加上(“”);
foreach(三元代码三元代码中的三元代码字母代码值)
{
三部曲。收集单词(单词);
}
返回单词;
}
_letterToNode.TryGetValue(前缀[0],输出三节点);
foreach(前缀中的字符c.Skip(1))
{
如果(节点为空)中断;
node.Children.TryGetValue(c,out节点);
}
节点?.collectionwords(words);
返回单词;
}
专用静态三元组FindOrAdd(字典letttonode,char键)
{
if(letterToNode.TryGetValue(key,out三节点))返回节点;
return letternode[键]=新的三节点();
}
私有类三节点
{
公共字典子项{get;}=new Dictionary();
公共字符串字{get;set;}
公共词(列表词)
{
如果(单词!=null)单词。添加(单词);
foreach(儿童中的三元组儿童。值)
{
儿童词汇;
}
}
}
}
+1回答得很好!我记不起它的确切名字了——特里亚!