@@ -10,10 +10,11 @@ def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
1010 of valid options sorted based on their similarity with the input.
1111 """
1212 options_by_distance = {}
13- input_threshold = len (input_ ) // 2
13+ lexical_distance = LexicalDistance (input_ )
1414
15+ input_threshold = len (input_ ) // 2
1516 for option in options :
16- distance = lexical_distance ( input_ , option )
17+ distance = lexical_distance . measure ( option )
1718 threshold = max (input_threshold , len (option ) // 2 , 1 )
1819 if distance <= threshold :
1920 options_by_distance [option ] = distance
@@ -25,7 +26,7 @@ def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
2526 )
2627
2728
28- def lexical_distance ( a_str : str , b_str : str ) -> int :
29+ class LexicalDistance :
2930 """Computes the lexical distance between strings A and B.
3031
3132 The "distance" between two strings is given by counting the minimum number of edits
@@ -34,27 +35,41 @@ def lexical_distance(a_str: str, b_str: str) -> int:
3435
3536 This distance can be useful for detecting typos in input or sorting.
3637 """
37- if a_str == b_str :
38- return 0
3938
40- a , b = a_str .lower (), b_str .lower ()
41- a_len , b_len = len (a ), len (b )
39+ _input : str
40+ _input_lower_case : str
41+ _cells : List [List [int ]]
42+
43+ def __init__ (self , input_ : str ):
44+ self ._input = input_
45+ self ._input_lower_case = input_ .lower ()
46+ self ._cells = []
47+
48+ def measure (self , option : str ):
49+ if self ._input == option :
50+ return 0
51+
52+ option_lower_case = option .lower ()
53+
54+ # Any case change counts as a single edit
55+ if self ._input_lower_case == option_lower_case :
56+ return 1
4257
43- # Any case change counts as a single edit
44- if a == b :
45- return 1
58+ d = self . _cells
59+ a , b = option_lower_case , self . _input_lower_case
60+ a_len , b_len = len ( a ), len ( b )
4661
47- d = [[j for j in range (0 , b_len + 1 )]]
48- for i in range (1 , a_len + 1 ):
49- d .append ([i ] + [0 ] * b_len )
62+ d = [[j for j in range (0 , b_len + 1 )]]
63+ for i in range (1 , a_len + 1 ):
64+ d .append ([i ] + [0 ] * b_len )
5065
51- for i in range (1 , a_len + 1 ):
52- for j in range (1 , b_len + 1 ):
53- cost = 0 if a [i - 1 ] == b [j - 1 ] else 1
66+ for i in range (1 , a_len + 1 ):
67+ for j in range (1 , b_len + 1 ):
68+ cost = 0 if a [i - 1 ] == b [j - 1 ] else 1
5469
55- d [i ][j ] = min (d [i - 1 ][j ] + 1 , d [i ][j - 1 ] + 1 , d [i - 1 ][j - 1 ] + cost )
70+ d [i ][j ] = min (d [i - 1 ][j ] + 1 , d [i ][j - 1 ] + 1 , d [i - 1 ][j - 1 ] + cost )
5671
57- if i > 1 and j > 1 and a [i - 1 ] == b [j - 2 ] and a [i - 2 ] == b [j - 1 ]:
58- d [i ][j ] = min (d [i ][j ], d [i - 2 ][j - 2 ] + cost )
72+ if i > 1 and j > 1 and a [i - 1 ] == b [j - 2 ] and a [i - 2 ] == b [j - 1 ]:
73+ d [i ][j ] = min (d [i ][j ], d [i - 2 ][j - 2 ] + cost )
5974
60- return d [a_len ][b_len ]
75+ return d [a_len ][b_len ]
0 commit comments