Una implementación de Levenshtein en C # y F #. La versión C # es 10 veces más rápida para dos cadenas de aproximadamente 1500 caracteres. C #: 69 ms, F # 867 ms. ¿Por qué? Por lo que puedo decir, ¿hacen exactamente lo mismo? No importa si es una versión Release o Debug build.
EDITAR: Si alguien viene aquí buscando específicamente la implementación Editar distancia, está roto. El código de trabajo está aquí .
C # :
private static int min3(int a, int b, int c)
{
return Math.Min(Math.Min(a, b), c);
}
public static int EditDistance(string m, string n)
{
var d1 = new int[n.Length];
for (int x = 0; x < d1.Length; x++) d1[x] = x;
var d0 = new int[n.Length];
for(int i = 1; i < m.Length; i++)
{
d0[0] = i;
var ui = m[i];
for (int j = 1; j < n.Length; j++ )
{
d0[j] = 1 + min3(d1[j], d0[j - 1], d1[j - 1] + (ui == n[j] ? -1 : 0));
}
Array.Copy(d0, d1, d1.Length);
}
return d0[n.Length - 1];
}
F # :
let min3(a, b, c) = min a (min b c)
let levenshtein (m:string) (n:string) =
let d1 = Array.init n.Length id
let d0 = Array.create n.Length 0
for i=1 to m.Length-1 do
d0.[0] <- i
let ui = m.[i]
for j=1 to n.Length-1 do
d0.[j] <- 1 + min3(d1.[j], d0.[j-1], d1.[j-1] + if ui = n.[j] then -1 else 0)
Array.blit d0 0 d1 0 n.Length
d0.[n.Length-1]
c#
performance
f#
inline
Robert Jeppesen
fuente
fuente
Respuestas:
El problema es que la
min3
función se compila como una función genérica que usa una comparación genérica (pensé que esto solo usaIComparable
, pero en realidad es más complicado: usaría una comparación estructural para los tipos de F # y es una lógica bastante compleja).En la versión C #, la función no es genérica (solo se necesita
int
). Puede mejorar la versión de F # agregando anotaciones de tipo (para obtener lo mismo que en C #):... o haciendo
min3
comoinline
(en cuyo caso, se especializaráint
cuando se use):Para una cadena aleatoria
str
de longitud 300, obtengo los siguientes números:fuente
inline
funciona como una plantilla de C ++, que se especializaría enint
función del sitio de la llamada.inline
. La razón por la cual el comportamiento predeterminado es diferente es porque se basa en genéricos .Net que son manejados por el tiempo de ejecución (y, posiblemente, no son tan buenos para escribir código numérico genérico). Sin embargo, el uso del comportamiento de C ++ en F # llevaría a una acumulación de código, porque F # usa genéricos mucho más.