/// <summary> /// Returns the minimal number of selection which intersection will only match all words with the given string /// at the given position. If no selection could be made, an empty list will be returned. /// </summary> /// <param name="position"></param> /// <param name="value"></param> /// <returns></returns> public ICollection <Selection <int> > GetSelections(int position, SubString value) { if (Options.MaxDepth <= 0) { return(Array.Empty <Selection <int> >()); } if (position < 0 || position + value.Length > roots.Length) { return(ListWithEmptySelection); } var nodes = new List <TrieNode>(value.Length / Options.MaxDepth + 2); /* * Separate the string into segments where each segment will correspond to a node. * * i.g. with MaxSubStringLength = 3: mes | sag | e */ // TODO: This splitting method is not optimal when we only use the minimal selection int i = 0; while (i < value.Length) { var node = GetNode(position + i, value.ToSubString(i)); if (node == null) { return(ListWithEmptySelection); } nodes.Add(node); i += node.Path.Length; } /* * If the last segment is smaller than MaxSubStringLength, its selection might be greater than necessary. * (see the example above) * This can be solved by adding character from the previous segment. */ if (nodes.Count > 1 && !nodes[nodes.Count - 1].IsLeaf) { var lastNode = nodes[nodes.Count - 1]; i = value.Length - lastNode.Path.Length; while (--i >= 0) { var n = GetNode(position + i, value.ToSubString(i)); if (i + n.Path.Length < value.Length) { break; } lastNode = n; } nodes[nodes.Count - 1] = lastNode; } // sort by ascending selection size nodes.Sort((a, b) => a.Selection.Count - b.Selection.Count); return(nodes.Select(n => n.Selection).ToList()); }