Skip to content

Commit 50a6c2e

Browse files
committed
suggestion_list: reuse matrix array
Replicates graphql/graphql-js@4b4a09d
1 parent 2ad7b0c commit 50a6c2e

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

src/graphql/pyutils/suggestion_list.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)