public static void Main()
var jw = new JaroWinkler();
Console.WriteLine(jw.Similarity("Krisz Kovacs", "Kov Krisztina"));
private const double DEFAULT_THRESHOLD = 0.7;
private const int THREE = 3;
private const double JW_COEF = 0.1;
private double Threshold { get; }
Threshold = DEFAULT_THRESHOLD;
public JaroWinkler(double threshold)
public double Similarity(string s1, string s2)
throw new ArgumentNullException(nameof(s1));
throw new ArgumentNullException(nameof(s2));
int[] mtp = Matches(s1, s2);
double j = ((m / s1.Length + m / s2.Length + (m - mtp[1]) / m))
jw = j + Math.Min(JW_COEF, 1.0 / mtp[THREE]) * mtp[2] * (1 - j);
public double Distance(string s1, string s2)
=> 1.0 - Similarity(s1, s2);
private static int[] Matches(string s1, string s2)
if (s1.Length > s2.Length)
int range = Math.Max(max.Length / 2 - 1, 0);
int[] match_indexes = Enumerable.Repeat(-1, min.Length).ToArray();
bool[] match_flags = new bool[max.Length];
for (int mi = 0; mi < min.Length; mi++)
for (int xi = Math.Max(mi - range, 0),
xn = Math.Min(mi + range + 1, max.Length); xi < xn; xi++)
if (!match_flags[xi] && c1 == max[xi])
char[] ms1 = new char[matches];
char[] ms2 = new char[matches];
for (int i = 0, si = 0; i < min.Length; i++)
if (match_indexes[i] != -1)
for (int i = 0, si = 0; i < max.Length; i++)
for (int mi = 0; mi < ms1.Length; mi++)
for (int mi = 0; mi < min.Length; mi++)
return new[] { matches, transpositions / 2, prefix, max.Length };