Per uno strumento di ricerca lato client ho bisogno di trovare la distanza Levenshtein di una parola con milioni di altre parole. Un utente dovrebbe essere in grado di confrontare un breve testo di circa venti parole con un libro. L'utente può farlo trovando le posizioni delle parole più caratterizzanti del testo nel libro. "Trovare luoghi" non significa cercare una corrispondenza esatta, ma quasi coincidere con levenshtein. Ho iniziato con le implementazioni già disponibili ma avevo bisogno di più velocità. Ho finito con questo:Qual è l'algoritmo di levenshtein più veloce per l'uso frequente e frequente
var rowA = new Uint16Array(1e6);
var rowB = new Uint16Array(1e6);
function levenshtein(s1, s2) {
var s1_len = s1.length, s2_len = s2.length, i1, i2 = 0, a, b, c, c2, i = 0;
if (s1_len === 0)
return s2_len;
if (s2_len === 0)
return s1_len;
while (i < s1_len)
rowA[i] = ++i;
while (i2 < s2_len) {
c2 = s2[i2];
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = rowA[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
rowB[i1] = b;
}
if (i2 === s2_len)
return b;
c2 = s2[i2];
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = rowB[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
rowA[i1] = b;
}
}
return b;
}
Come vedi ho usato le tecniche di come mettere gli oggetti fuori della funzione, al fine di ri usarli. Mi sono anche ripetuto un po 'linearizzando il loop in qualche modo. Potrebbe essere più veloce? Sono curioso del tuo consiglio.
Aggiornamento: Dopo suggerimenti da Bergi e ancora un po 'il pensiero mi è venuto a questa soluzione:
var row = new Uint16Array(1e6);
function levenshtein(s1, s2) {
var s1_len = s1.length, s2_len = s2.length, i2 = 1, a, b = 0, c, c2, i1 = 0;
if (s1_len === 0)
return s2_len;
if (s2_len === 0)
return s1_len;
c2 = s2[0];
if (s1[0] === c2) {
while (i1 < s1_len) {
row[i1] = i1++;
}
b = s1_len - 1;
} else {
row[0] = 1;
++b;
if (s1_len > 1)
for (i1 = 1; i1 < s1_len; ++i1) {
if (s1[i1] === c2) {
row[i1] = b;
for (++i1; i1 < s1_len; ++i1) {
row[i1] = ++b;
}
} else {
row[i1] = ++b;
}
}
}
if (s2_len > 1)
while (i2 < s2_len) {
c2 = s2[i2];
c = i2 + (s1[0] !== c2);
a = row[0];
++i2;
b = i2 < a ? (i2 < c ? i2 + 1 : c) : (a < c ? a + 1 : c);
row[0] = b;
if (s1_len > 1) {
for (i1 = 1; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = row[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
row[i1] = b;
}
}
}
return b;
}
Anche questo è molto più veloce. Non riesco a spremere di più. Continuo a cercare altre idee e proverò ancora.
Conoscete questa discussione: http://stackoverflow.com/questions/11919065/sort-an-array-by-the-levenshtein-distance-with-best-performance-in-javascript? –
Sì, lo sono, ma levDist ('conoscenza', 'configurato') mi dà 8 mentre mi aspettavo 9. Quindi non ne sono sicuro. –
@MarcodeWit: I commenti sulla risposta accettata spiegano che il codice lì fa Damerau-Levensthein, che dà 8 per le tue parole. – Bergi