public ArgsTrie(IEnumerable <ArgsMap <TValue> > mappings, bool caseSensitive) : base(DefaultTrieWidth) { this.CaseSensitive = caseSensitive; // load trie foreach (ArgsMap <TValue> map in mappings) { TrieNode <char, TValue> node = this; string prefix = caseSensitive ? map.Prefix : map.Prefix.ToLowerInvariant(); // build out the path for StartToken foreach (char ch in prefix) { if (!node.Contains(ch)) { node[ch] = new TrieNode <char, TValue>(DefaultTrieWidth); } node = (TrieNode <char, TValue>)node[ch]; } // at the end of the Prefix is the Index node.Value = map.Index; } }
/* * Finds the exact node that corresponds to a search query * returns null if node doesn't exist */ public TrieNode?FindNode(string search) { bool first = true; TrieNode current = new TrieNode(' '); foreach (char c in search) { if (first) { first = false; if (roots.ContainsKey(c)) { current = roots[c]; } else { return(null); } continue; } if (current.Contains(c)) { current = current.edges[c]; } else { return(null); } } return(current); }
private void BuildTrie(string v) { TrieNode current = _TrieNode; for (int i = 0; i < v.Length; i++) { if (!current.Contains(v[i])) { current.Put(v[i], new TrieNode()); } else { current = current.Child['a' - v[i]]; } } current.Word = v; }
public string Search(string input) { string result = ""; // maintain a stack of traversed nodes Stack <TrieNode> foundNodes = new Stack <TrieNode>(); TrieNode currentNode = root; // for each character in a given input string foreach (char i in input) { // if not found at current traversal, stop search if (!currentNode.Contains(i, out currentNode)) { break; } // found, foundNodes.Push(currentNode); } // because only the trie knows the termination of prefix strings // we may have traversed a substring. // for example with given prefix '12' and '1234' and a input of '1234' // we have a tree representation of 1-2(end)-3-4(end) // we will have traverse to 1-2-3 and need to back-up to an ending node // remove any trailing non-terminating nodes (End is false) while (foundNodes.Count > 0 && !foundNodes.Peek().End) { foundNodes.Pop(); } // concat value while (foundNodes.Count > 0) { currentNode = foundNodes.Pop(); result = currentNode.Value + result; } return(result); }
public void Add(string item) { bool first = true; TrieNode current = new TrieNode(' '); foreach (char c in item.ToLower()) { if (first) { current = roots[c]; first = false; continue; } if (!current.Contains(c)) { current.Add(new TrieNode(c)); } current = current.edges[c]; } }
public FilterTrie(IEnumerable <ReadFilter> filters) : base(DefaultTrieWidth) { // load trie foreach (ReadFilter filter in filters) { TrieNode <char, string> node = this; // build out the path for StartToken foreach (char ch in filter.StartToken) { if (!node.Contains(ch)) { node[ch] = new TrieNode <char, string>(DefaultTrieWidth); } node = (TrieNode <char, string>)node[ch]; } // at the end of StartToken path is the EndToken node.Value = filter.EndToken; } }
/** Returns if the word is in the trie. */ public bool Search(string word) { return(treeRoot.Contains(word)); }
public void TestTrieNode() { var root = new TrieNode(); Assert.AreEqual(1, root.NodeCount); Assert.AreEqual(0, root.WordCount); Assert.IsFalse(root.Contains("")); Assert.IsFalse(root.Contains("a")); root.Add(""); Assert.AreEqual(1, root.NodeCount); Assert.AreEqual(1, root.WordCount); Assert.IsTrue(root.Contains("")); Assert.IsFalse(root.Contains("a")); root.Add("ab"); Assert.AreEqual(3, root.NodeCount); Assert.AreEqual(2, root.WordCount); Assert.IsTrue(root.Contains("")); Assert.IsFalse(root.Contains("a")); Assert.IsFalse(root.Contains("ba")); Assert.IsTrue(root.Contains("ab")); root.Add("ac"); Assert.AreEqual(4, root.NodeCount); Assert.AreEqual(3, root.WordCount); Assert.IsTrue(root.Contains("")); Assert.IsFalse(root.Contains("a")); Assert.IsTrue(root.Contains("ab")); Assert.IsTrue(root.Contains("ac")); root.Delete("ab"); Assert.AreEqual(3, root.NodeCount); Assert.AreEqual(2, root.WordCount); Assert.IsTrue(root.Contains("")); Assert.IsFalse(root.Contains("a")); Assert.IsFalse(root.Contains("ab")); Assert.IsTrue(root.Contains("ac")); root.Delete("ac"); Assert.AreEqual(1, root.NodeCount); Assert.AreEqual(1, root.WordCount); root.Delete(""); Assert.AreEqual(1, root.NodeCount); Assert.AreEqual(0, root.WordCount); }
/// <summary> /// Returns the collection of items similar to the word. This implementation was inspired by /// the following python implementation - https://github.com/teoryn/SpellCheck /// </summary> /// <param name="word">Word for which similar items should be found</param> /// <param name="maxDist">Maximum difference between strings (defined as edit distance)</param> /// <param name="node">Current trie node</param> /// <param name="built">The part which has been already built</param> /// <returns>The collection of items similar to the word</returns> public IEnumerable <string> FindSimilar(string word, int maxDist, TrieNode node, string built) { var result = new List <string>(); if (maxDist < 0) { return(result); } if (node == null) { node = root; } var childNodes = node.GetAllChildren(); // trying to insert every char for this trie node for (int i = 0; i < childNodes.Count(); i++) { if (childNodes[i] != null) { result.AddRange(FindSimilar(word, maxDist - 1, childNodes[i], built + (char)(i + node.BaseChar))); } } // if there are no letters in word, then stop recursing if (string.IsNullOrEmpty(word)) { if (node.IsEntry) { result.Add(built); } return(result); } // if current trie node contains the first char of the word if (node.Contains(word[0])) { // then try to use it and do not perform any edit on this step result.AddRange(FindSimilar(word.Substring(1), maxDist, node.GetChild(word[0]), built + word[0])); } // This check lets us avoid unnecessary recursive calls if (maxDist == 0) { return(result); } // trying to remove the first char from the word result.AddRange(FindSimilar(word.Substring(1), maxDist - 1, node, built)); // trying to replace the first char from the word with one of the chars from the current trie node for (int i = 0; i < childNodes.Count(); i++) { if (childNodes[i] != null && (char)(i + node.BaseChar) != word[0]) { result.AddRange(FindSimilar(word.Substring(1), maxDist - 1, childNodes[i], built + (char)(i + node.BaseChar))); } } // if the word is at least two chars long and the second char is contained in the current trie node if (word.Length > 1 && node.Contains(word[1])) { // then try to transpose the first and the seconds chars from the word result.AddRange(FindSimilar(word[0] + word.Substring(2), maxDist - 1, node.GetChild(word[1]), built + word[1])); } return(result); }