Skip to content

Commit 4b4a09d

Browse files
committed
suggestionList: reuse matrix array
1 parent 7a4cbbb commit 4b4a09d

File tree

1 file changed

+46
-34
lines changed

1 file changed

+46
-34
lines changed

src/jsutils/suggestionList.js

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export default function suggestionList(
99
options: $ReadOnlyArray<string>,
1010
): Array<string> {
1111
const optionsByDistance = Object.create(null);
12+
const lexicalDistance = new LexicalDistance(input);
13+
1214
const inputThreshold = input.length / 2;
1315
for (const option of options) {
14-
const distance = lexicalDistance(input, option);
16+
const distance = lexicalDistance.measure(option);
1517
const threshold = Math.max(inputThreshold, option.length / 2, 1);
1618
if (distance <= threshold) {
1719
optionsByDistance[option] = distance;
@@ -36,50 +38,60 @@ export default function suggestionList(
3638
* of 1.
3739
*
3840
* This distance can be useful for detecting typos in input or sorting
39-
*
40-
* @param {string} a
41-
* @param {string} b
42-
* @return {int} distance in number of edits
4341
*/
44-
function lexicalDistance(aStr, bStr) {
45-
if (aStr === bStr) {
46-
return 0;
42+
class LexicalDistance {
43+
_input: string;
44+
_inputLowerCase: string;
45+
_cells: Array<Array<number>>;
46+
47+
constructor(input: string) {
48+
this._input = input;
49+
this._inputLowerCase = input.toLowerCase();
50+
this._cells = [];
4751
}
4852

49-
const d = [];
50-
const a = aStr.toLowerCase();
51-
const b = bStr.toLowerCase();
52-
const aLength = a.length;
53-
const bLength = b.length;
53+
measure(option: string): number {
54+
if (this._input === option) {
55+
return 0;
56+
}
5457

55-
// Any case change counts as a single edit
56-
if (a === b) {
57-
return 1;
58-
}
58+
const optionLowerCase = option.toLowerCase();
5959

60-
for (let i = 0; i <= aLength; i++) {
61-
d[i] = [i];
62-
}
60+
// Any case change counts as a single edit
61+
if (this._inputLowerCase === optionLowerCase) {
62+
return 1;
63+
}
6364

64-
for (let j = 1; j <= bLength; j++) {
65-
d[0][j] = j;
66-
}
65+
const d = this._cells;
66+
const a = optionLowerCase;
67+
const b = this._inputLowerCase;
68+
const aLength = a.length;
69+
const bLength = b.length;
70+
71+
for (let i = 0; i <= aLength; i++) {
72+
d[i] = [i];
73+
}
6774

68-
for (let i = 1; i <= aLength; i++) {
6975
for (let j = 1; j <= bLength; j++) {
70-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
76+
d[0][j] = j;
77+
}
7178

72-
d[i][j] = Math.min(
73-
d[i - 1][j] + 1,
74-
d[i][j - 1] + 1,
75-
d[i - 1][j - 1] + cost,
76-
);
79+
for (let i = 1; i <= aLength; i++) {
80+
for (let j = 1; j <= bLength; j++) {
81+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
7782

78-
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
79-
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
83+
d[i][j] = Math.min(
84+
d[i - 1][j] + 1,
85+
d[i][j - 1] + 1,
86+
d[i - 1][j - 1] + cost,
87+
);
88+
89+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
90+
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
91+
}
8092
}
8193
}
82-
}
8394

84-
return d[aLength][bLength];
95+
return d[aLength][bLength];
96+
}
8597
}

0 commit comments

Comments
 (0)