@@ -10,10 +10,11 @@ def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
10
10
of valid options sorted based on their similarity with the input.
11
11
"""
12
12
options_by_distance = {}
13
- input_threshold = len (input_ ) // 2
13
+ lexical_distance = LexicalDistance (input_ )
14
14
15
+ input_threshold = len (input_ ) // 2
15
16
for option in options :
16
- distance = lexical_distance ( input_ , option )
17
+ distance = lexical_distance . measure ( option )
17
18
threshold = max (input_threshold , len (option ) // 2 , 1 )
18
19
if distance <= threshold :
19
20
options_by_distance [option ] = distance
@@ -25,7 +26,7 @@ def suggestion_list(input_: str, options: Collection[str]) -> List[str]:
25
26
)
26
27
27
28
28
- def lexical_distance ( a_str : str , b_str : str ) -> int :
29
+ class LexicalDistance :
29
30
"""Computes the lexical distance between strings A and B.
30
31
31
32
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:
34
35
35
36
This distance can be useful for detecting typos in input or sorting.
36
37
"""
37
- if a_str == b_str :
38
- return 0
39
38
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
42
57
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 )
46
61
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 )
50
65
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
54
69
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 )
56
71
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 )
59
74
60
- return d [a_len ][b_len ]
75
+ return d [a_len ][b_len ]
0 commit comments