Initial
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MileageTraker.Web.Utility
|
||||
{
|
||||
public static class Algorithms
|
||||
{
|
||||
public static double Similarity<T>(IEnumerable<T> x, IEnumerable<T> y)
|
||||
where T : IEquatable<T>
|
||||
{
|
||||
return 1.0 - (double)EditDistance(x, y) / Math.Max(x.Count(), y.Count());
|
||||
}
|
||||
|
||||
/// <SUMMARY>Computes the Levenshtein Edit Distance between two enumerables.</SUMMARY>
|
||||
/// <TYPEPARAM name="T">The type of the items in the enumerables.</TYPEPARAM>
|
||||
/// <PARAM name="x">The first enumerable.</PARAM>
|
||||
/// <PARAM name="y">The second enumerable.</PARAM>
|
||||
/// <RETURNS>The edit distance.</RETURNS>
|
||||
/// <remarks>http://blogs.msdn.com/b/toub/archive/2006/05/05/590814.aspx</remarks>
|
||||
public static int EditDistance<T>(IEnumerable<T> x, IEnumerable<T> y)
|
||||
where T : IEquatable<T>
|
||||
{
|
||||
// Validate parameters
|
||||
if (x == null) throw new ArgumentNullException("x");
|
||||
if (y == null) throw new ArgumentNullException("y");
|
||||
|
||||
// Convert the parameters into IList instances
|
||||
// in order to obtain indexing capabilities
|
||||
var first = x as IList<T> ?? new List<T>(x);
|
||||
var second = y as IList<T> ?? new List<T>(y);
|
||||
|
||||
// Get the length of both. If either is 0, return
|
||||
// the length of the other, since that number of insertions
|
||||
// would be required.
|
||||
int n = first.Count, m = second.Count;
|
||||
if (n == 0) return m;
|
||||
if (m == 0) return n;
|
||||
|
||||
// Rather than maintain an entire matrix (which would require O(n*m) space),
|
||||
// just store the current row and the next row, each of which has a length m+1,
|
||||
// so just O(m) space. Initialize the current row.
|
||||
int curRow = 0, nextRow = 1;
|
||||
var rows = new[] {new int[m + 1], new int[m + 1]};
|
||||
for (var j = 0; j <= m; ++j) rows[curRow][j] = j;
|
||||
|
||||
// For each virtual row (since we only have physical storage for two)
|
||||
for (var i = 1; i <= n; ++i)
|
||||
{
|
||||
// Fill in the values in the row
|
||||
rows[nextRow][0] = i;
|
||||
for (var j = 1; j <= m; ++j)
|
||||
{
|
||||
int dist1 = rows[curRow][j] + 1;
|
||||
int dist2 = rows[nextRow][j - 1] + 1;
|
||||
int dist3 = rows[curRow][j - 1] +
|
||||
(first[i - 1].Equals(second[j - 1]) ? 0 : 1);
|
||||
|
||||
rows[nextRow][j] = Math.Min(dist1, Math.Min(dist2, dist3));
|
||||
}
|
||||
|
||||
// Swap the current and next rows
|
||||
if (curRow == 0)
|
||||
{
|
||||
curRow = 1;
|
||||
nextRow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
curRow = 0;
|
||||
nextRow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the computed edit distance
|
||||
return rows[curRow][m];
|
||||
}
|
||||
|
||||
public static bool IsChronological(DateTime existingDate, int existingNumber, DateTime date, int number)
|
||||
{
|
||||
return existingDate == date
|
||||
|| existingNumber == number
|
||||
|| existingDate < date && existingNumber < number
|
||||
|| existingDate > date && existingNumber > number;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user