@@ -25,16 +25,6 @@ public interface ILevenshtrie<T>
25
25
LevenshtrieSearchResult < T > [ ] Search < TSearchState > ( TSearchState searcher )
26
26
where TSearchState : ILevenshtomatonExecutionState < TSearchState > ;
27
27
28
- /// <summary>
29
- /// Searches for values whose keys begin with a prefix accepted by the search state,
30
- /// but without considering further edits beyond the matched prefix.
31
- /// </summary>
32
- /// <typeparam name="TSearchState">The automaton state used to guide the prefix traversal.</typeparam>
33
- /// <param name="searcher">The automaton execution state.</param>
34
- /// <returns>An array of values with matching prefixes.</returns>
35
- T [ ] SearchByPrefix < TSearchState > ( TSearchState searcher )
36
- where TSearchState : ILevenshtomatonExecutionState < TSearchState > ;
37
-
38
28
/// <summary>
39
29
/// Lazily searches for values whose keys are accepted by the specified automaton execution state.
40
30
/// Results are returned in arbitrary order and evaluated on-demand.
@@ -48,20 +38,6 @@ T[] SearchByPrefix<TSearchState>(TSearchState searcher)
48
38
/// </remarks>
49
39
IEnumerable < LevenshtrieSearchResult < T > > EnumerateSearch < TSearchState > ( TSearchState searcher )
50
40
where TSearchState : ILevenshtomatonExecutionState < TSearchState > ;
51
-
52
- /// <summary>
53
- /// Lazily searches for values whose keys begin with a prefix accepted by the automaton execution state.
54
- /// Results are returned in arbitrary order and evaluated on-demand.
55
- /// </summary>
56
- /// <typeparam name="TSearchState">The automaton state used to guide the traversal.</typeparam>
57
- /// <param name="searcher">The automaton execution state.</param>
58
- /// <returns>An enumerable of values with matching prefixes.</returns>
59
- /// <remarks>
60
- /// This method avoids allocating a full result array up front, and can be more efficient
61
- /// when only a subset of results are consumed. However, it may be slower when all results are needed.
62
- /// </remarks>
63
- IEnumerable < T > EnumerateSearchByPrefix < TSearchState > ( TSearchState searcher )
64
- where TSearchState : ILevenshtomatonExecutionState < TSearchState > ;
65
41
}
66
42
67
43
public static class LevenshtrieExtensions
@@ -113,6 +89,17 @@ public static LevenshtrieSearchResult<T>[] Search<T>(this ILevenshtrie<T> @this,
113
89
public static LevenshtrieSearchResult < T > [ ] Search < T > ( this ILevenshtrie < T > @this , LevenshtomatonExecutionState searcher )
114
90
=> @this . Search ( searcher ) ;
115
91
92
+ /// <summary>
93
+ /// Searches for values whose keys begin with a prefix accepted by the search state,
94
+ /// but without considering further edits beyond the matched prefix.
95
+ /// </summary>
96
+ /// <typeparam name="TSearchState">The automaton state used to guide the prefix traversal.</typeparam>
97
+ /// <param name="searcher">The automaton execution state.</param>
98
+ /// <returns>An array of matched values and their corresponding edit distances.</returns>
99
+ public static LevenshtrieSearchResult < T > [ ] SearchByPrefix < T , TSearchState > ( this ILevenshtrie < T > @this , TSearchState searcher )
100
+ where TSearchState : ILevenshtomatonExecutionState < TSearchState >
101
+ => @this . Search ( PrefixTrackingLevenshtomatonExecutionState < TSearchState > . Start ( searcher ) ) ;
102
+
116
103
/// <summary>
117
104
/// Searches for values whose keys begin with the specified prefix text,
118
105
/// allowing up to the given edit distance. Results are returned in arbitrary order.
@@ -123,11 +110,12 @@ public static LevenshtrieSearchResult<T>[] Search<T>(this ILevenshtrie<T> @this,
123
110
/// <param name="maxEditDistance">The maximum allowed edit distance.</param>
124
111
/// <param name="metric">The edit distance metric to use.</param>
125
112
/// <returns>An array of values whose keys begin with the given prefix.</returns>
126
- public static T [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , string text , int maxEditDistance , LevenshtypoMetric metric = LevenshtypoMetric . Levenshtein )
113
+ public static LevenshtrieSearchResult < T > [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , string text , int maxEditDistance , LevenshtypoMetric metric = LevenshtypoMetric . Levenshtein )
127
114
{
128
115
var automaton = LevenshtomatonFactory . Instance . Construct ( text , maxEditDistance , ignoreCase : @this . IgnoreCase , metric : metric ) ;
129
116
return @this . SearchByPrefix ( automaton ) ;
130
117
}
118
+
131
119
/// <summary>
132
120
/// Searches for values whose keys are accepted by the given automaton, restricted to prefix matches.
133
121
/// Results are returned in arbitrary order.
@@ -139,15 +127,15 @@ public static T[] SearchByPrefix<T>(this ILevenshtrie<T> @this, string text, int
139
127
/// <exception cref="ArgumentException">
140
128
/// Thrown if the automaton's case sensitivity does not match the trie's configuration.
141
129
/// </exception>
142
- public static T [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , Levenshtomaton automaton )
130
+ public static LevenshtrieSearchResult < T > [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , Levenshtomaton automaton )
143
131
{
144
132
if ( automaton . IgnoreCase != @this . IgnoreCase )
145
133
{
146
134
throw new ArgumentException ( "Case sensitivity of automaton does not match." ) ;
147
135
}
148
136
149
- var executor = @this as ILevenshtomatonExecutor < SearchByPrefixWrapper < T [ ] > > ?? new TrieExecutor < T > ( @this ) ;
150
- return automaton . Execute ( executor ) . Wrapped ;
137
+ var executor = new TriePrefixExecutor < T > ( @this ) ;
138
+ return automaton . Execute < LevenshtrieSearchResult < T > [ ] > ( executor ) ;
151
139
}
152
140
153
141
/// <summary>
@@ -158,8 +146,8 @@ public static T[] SearchByPrefix<T>(this ILevenshtrie<T> @this, Levenshtomaton a
158
146
/// <param name="this">The trie to search.</param>
159
147
/// <param name="searcher">A boxed automaton execution state.</param>
160
148
/// <returns>Values whose keys match the prefix condition.</returns>
161
- public static T [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , LevenshtomatonExecutionState searcher )
162
- => @this . SearchByPrefix < LevenshtomatonExecutionState > ( searcher ) ;
149
+ public static LevenshtrieSearchResult < T > [ ] SearchByPrefix < T > ( this ILevenshtrie < T > @this , LevenshtomatonExecutionState searcher )
150
+ => @this . SearchByPrefix < T , LevenshtomatonExecutionState > ( searcher ) ;
163
151
164
152
/// <summary>
165
153
/// Lazily searches for approximate matches using a Levenshtein automaton, evaluated on-demand.
@@ -223,7 +211,7 @@ public static IEnumerable<LevenshtrieSearchResult<T>> EnumerateSearch<T>(this IL
223
211
/// Lazily evaluates prefix matches. Uses less memory than eager prefix search,
224
212
/// and is efficient when only a subset of results is needed.
225
213
/// </remarks>
226
- public static IEnumerable < T > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , string text , int maxEditDistance , LevenshtypoMetric metric = LevenshtypoMetric . Levenshtein )
214
+ public static IEnumerable < LevenshtrieSearchResult < T > > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , string text , int maxEditDistance , LevenshtypoMetric metric = LevenshtypoMetric . Levenshtein )
227
215
{
228
216
var automaton = LevenshtomatonFactory . Instance . Construct ( text , maxEditDistance , ignoreCase : @this . IgnoreCase , metric : metric ) ;
229
217
return @this . EnumerateSearchByPrefix ( automaton ) ;
@@ -239,15 +227,15 @@ public static IEnumerable<T> EnumerateSearchByPrefix<T>(this ILevenshtrie<T> @th
239
227
/// <exception cref="ArgumentException">
240
228
/// Thrown if the automaton's case sensitivity does not match the trie's configuration.
241
229
/// </exception>
242
- public static IEnumerable < T > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , Levenshtomaton automaton )
230
+ public static IEnumerable < LevenshtrieSearchResult < T > > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , Levenshtomaton automaton )
243
231
{
244
232
if ( automaton . IgnoreCase != @this . IgnoreCase )
245
233
{
246
234
throw new ArgumentException ( "Case sensitivity of automaton does not match." ) ;
247
235
}
248
236
249
- var executor = @this as ILevenshtomatonExecutor < SearchByPrefixWrapper < IEnumerable < T > > > ?? new TrieExecutor < T > ( @this ) ;
250
- return automaton . Execute ( executor ) . Wrapped ;
237
+ var executor = new TriePrefixExecutor < T > ( @this ) ;
238
+ return automaton . Execute < IEnumerable < LevenshtrieSearchResult < T > > > ( executor ) ;
251
239
}
252
240
253
241
/// <summary>
@@ -257,25 +245,42 @@ public static IEnumerable<T> EnumerateSearchByPrefix<T>(this ILevenshtrie<T> @th
257
245
/// <param name="this">The trie to search.</param>
258
246
/// <param name="searcher">A boxed automaton execution state.</param>
259
247
/// <returns>An enumerable of values with matching prefixes.</returns>
260
- public static IEnumerable < T > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , LevenshtomatonExecutionState searcher )
261
- => @this . EnumerateSearchByPrefix < LevenshtomatonExecutionState > ( searcher ) ;
248
+ public static IEnumerable < LevenshtrieSearchResult < T > > EnumerateSearchByPrefix < T > ( this ILevenshtrie < T > @this , LevenshtomatonExecutionState searcher )
249
+ => @this . EnumerateSearchByPrefix < T , LevenshtomatonExecutionState > ( searcher ) ;
250
+
251
+ /// <summary>
252
+ /// Lazily searches for values whose keys begin with a prefix accepted by the automaton execution state.
253
+ /// Results are returned in arbitrary order and evaluated on-demand.
254
+ /// </summary>
255
+ /// <typeparam name="TSearchState">The automaton state used to guide the traversal.</typeparam>
256
+ /// <param name="searcher">The automaton execution state.</param>
257
+ /// <returns>An array of matched values and their corresponding edit distances.</returns>
258
+ /// <remarks>
259
+ /// This method avoids allocating a full result array up front, and can be more efficient
260
+ /// when only a subset of results are consumed. However, it may be slower when all results are needed.
261
+ /// </remarks>
262
+ public static IEnumerable < LevenshtrieSearchResult < T > > EnumerateSearchByPrefix < T , TSearchState > ( this ILevenshtrie < T > @this , TSearchState searcher )
263
+ where TSearchState : ILevenshtomatonExecutionState < TSearchState >
264
+ => @this . EnumerateSearch ( PrefixTrackingLevenshtomatonExecutionState < TSearchState > . Start ( searcher ) ) ;
262
265
263
266
private class TrieExecutor < T > ( ILevenshtrie < T > trie ) :
264
267
ILevenshtomatonExecutor < LevenshtrieSearchResult < T > [ ] > ,
265
- ILevenshtomatonExecutor < IEnumerable < LevenshtrieSearchResult < T > > > ,
266
- ILevenshtomatonExecutor < SearchByPrefixWrapper < T [ ] > > ,
267
- ILevenshtomatonExecutor < SearchByPrefixWrapper < IEnumerable < T > > >
268
+ ILevenshtomatonExecutor < IEnumerable < LevenshtrieSearchResult < T > > >
268
269
{
269
270
public LevenshtrieSearchResult < T > [ ] ExecuteAutomaton < TState > ( TState executionState ) where TState : struct , ILevenshtomatonExecutionState < TState >
270
271
=> trie . Search ( executionState ) ;
271
272
272
273
IEnumerable < LevenshtrieSearchResult < T > > ILevenshtomatonExecutor < IEnumerable < LevenshtrieSearchResult < T > > > . ExecuteAutomaton < TState > ( TState executionState )
273
274
=> trie . EnumerateSearch ( executionState ) ;
275
+ }
276
+ private class TriePrefixExecutor < T > ( ILevenshtrie < T > trie ) :
277
+ ILevenshtomatonExecutor < LevenshtrieSearchResult < T > [ ] > ,
278
+ ILevenshtomatonExecutor < IEnumerable < LevenshtrieSearchResult < T > > >
279
+ {
280
+ public LevenshtrieSearchResult < T > [ ] ExecuteAutomaton < TState > ( TState executionState ) where TState : struct , ILevenshtomatonExecutionState < TState >
281
+ => trie . SearchByPrefix ( executionState ) ;
274
282
275
- SearchByPrefixWrapper < T [ ] > ILevenshtomatonExecutor < SearchByPrefixWrapper < T [ ] > > . ExecuteAutomaton < TState > ( TState executionState )
276
- => new ( trie . SearchByPrefix ( executionState ) ) ;
277
-
278
- SearchByPrefixWrapper < IEnumerable < T > > ILevenshtomatonExecutor < SearchByPrefixWrapper < IEnumerable < T > > > . ExecuteAutomaton < TState > ( TState executionState )
279
- => new ( trie . EnumerateSearchByPrefix ( executionState ) ) ;
283
+ IEnumerable < LevenshtrieSearchResult < T > > ILevenshtomatonExecutor < IEnumerable < LevenshtrieSearchResult < T > > > . ExecuteAutomaton < TState > ( TState executionState )
284
+ => trie . EnumerateSearchByPrefix ( executionState ) ;
280
285
}
281
286
}
0 commit comments