using System;
namespace Developpez.Dotnet.Algorithms
{
///
/// Fournit des méthodes permettant d'évaluer la similarité entre 2 chaînes de caractères,
/// selon l'algorithme de la distance de Levenshtein.
///
/// L'algorithme de la distance de Levenshtein est décrit ici :
/// http://en.wikipedia.org/wiki/Levenshtein_distance.
///
public static class Levenshtein
{
///
/// Calcule la distance de Levenshtein entre 2 chaînes de caractères.
///
/// Première chaîne à comparer.
/// Seconde chaîne à comparer.
/// true pour tenir compte de la casse, false sinon.
/// La distance de Levenshtein entre les 2 chaînes.
///
///
/// - La distance de Levenshtein est toujours supérieure ou égale à la différence de longueur entre les 2 chaines
/// - La distance de Levenshtein est toujours inférieure ou égale à la longueur de la plus longue chaine
/// - La distance de Levenshtein entre 2 chaines identiques est 0
///
///
public static int ComputeDistance(string a, string b, bool caseSensitive)
{
if (!caseSensitive)
{
a = a.ToLower();
b = b.ToLower();
}
int m = a.Length;
int n = b.Length;
int[,] d = new int[m + 1, n + 1];
for (int i = 0; i <= m; i++)
d[i, 0] = i;
for (int i = 0; i <= n; i++)
d[0, i] = i;
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
int cost;
if (a[i - 1] == b[j - 1])
cost = 0;
else
cost = 1;
d[i, j] = Min(d[i - 1, j] + 1,
d[i, j - 1] + 1,
d[i - 1, j - 1] + cost);
}
}
return d[m, n];
}
///
/// Calcule le coefficient de corrélation entre 2 chaînes, sur la base de la distance de Levenshtein
///
/// Première chaîne à comparer
/// Seconde chaîne à comparer
/// true pour tenir compte de la casse, false sinon
/// Le coefficient de corrélation entre les 2 chaînes. Cette valeur est comprise entre 0 (chaînes complètement différentes) et 1 (chaînes identiques)
/// Ce coefficient est calculé selon la formule suivante : 1 - d/L, où d est la distance de Levenshtein entre les 2 chaînes, et L la longueur de la plus longue chaîne.
public static double ComputeCorrelation(string a, string b, bool caseSensitive)
{
int distance = ComputeDistance(a, b, caseSensitive);
int longest = Max(a.Length, b.Length);
return 1 - (double)distance / longest;
}
private static T Min(T arg0, params T[] args) where T : IComparable
{
T min = arg0;
for (int i = 0; i < args.Length; i++)
{
T x = args[i];
if (x.CompareTo(min) < 0)
min = x;
}
return min;
}
private static T Max(T arg0, params T[] args) where T : IComparable
{
T max = arg0;
for (int i = 0; i < args.Length; i++)
{
T x = args[i];
if (x.CompareTo(max) > 0)
max = x;
}
return max;
}
}
}