using System.Collections; namespace Common.Distance; public static class Calculator { /// /// Calculates the levenshtein distance between two enumerables /// /// /// /// /// public static double GetDistance(T reference, T? hypothesis) where T : IEnumerable { // Setup var refArr = reference.Cast().ToArray(); var hypArr = hypothesis?.Cast().ToArray() ?? Array.Empty(); var distance = new int[refArr.Length + 1, hypArr.Length + 1]; // Fill matrix for (var x = 0; x <= refArr.Length; x++) { // Reference on X axis distance[x, 0] = x; } for (var y = 0; y <= hypArr.Length; y++) { // Hypothesis on Y axis distance[0, y] = y; } // Calculate distance for (var x = 0; x < refArr.Length; x++) { for (var y = 0; y < hypArr.Length; y++) { // BL Cost depends on whether the two elements are equal var cost = Equals(refArr[x], hypArr[y]) ? 0 : 1; // Apply distance mask var c1 = distance[x, y] + cost; // Bottom left var c2 = distance[x, y + 1] + 1; // Top left var c3 = distance[x + 1, y] + 1; // Bottom right distance[x + 1, y + 1] = Min(c1, c2, c3); // Top right } } return distance[refArr.Length, hypArr.Length]; } private static T Min(params T[] values) { if (!values.Any()) { throw new ArgumentException("Array cannot be empty", nameof(values)); } return values.Min()!; } }