I am working on an application that needs to display different columns of information naturally sorted. A while back I found this article that has a good description and code. I modified it some since we have columns that also show dates and ended up with this:
public class NaturalComparer : Comparer<string>, IDisposable
{
private Dictionary<string, string[]> table;
public NaturalComparer()
{
table = new Dictionary<string, string[]>();
}
public void Dispose()
{
table.Clear();
table = null;
}
public override int Compare(string x, string y)
{
if (x == y)
{
return 0;
}
DateTime xValueD, yValueD;
if (DateTime.TryParse(x, out xValueD) && DateTime.TryParse(y, out yValueD))
return xValueD.CompareTo(yValueD);
string[] x1, y1;
if (!table.TryGetValue(x, out x1))
{
x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
table.Add(x, x1);
}
if (!table.TryGetValue(y, out y1))
{
y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
table.Add(y, y1);
}
for (int i = 0; i < x1.Length && i < y1.Length; i++)
{
if (x1[i] != y1[i])
{
return PartCompare(x1[i], y1[i]);
}
}
if (y1.Length > x1.Length)
{
return 1;
}
else if (x1.Length > y1.Length)
{
return -1;
}
else
{
return 0;
}
}
private static int PartCompare(string left, string right)
{
int x, y;
if (!int.TryParse(left, out x))
{
return left.CompareTo(right);
}
if (!int.TryParse(right, out y))
{
return left.CompareTo(right);
}
return x.CompareTo(y);
}
}
Now it also needs to process a special type of string data and it is not doing what we need. The strings show information of ranges of data and they look like this:
string[] list = { "Empty Values","x<0" , "1000.0 < x <=1500.0", "900.0 < x <= 1000.0","3000.0 < x <= 3500.0", "800.0 < x <=900.0" };
Sorted it should look like:
x < 0
800.0 < x <= 900.0
900.0 < x <= 1000.0
1000.0 < x <= 1500.0
3000.0 < x <= 3500.0
Empty Values
However, it ends up with:
800.0 < x <= 900.0
900.0 < x <= 1000.0
1000.0 < x <= 1500.0
3000.0 < x <= 3500.0
Empty Values
x < 0
So, logically I think it is doing what it is designed to do, because it picks on the letter and sorts based on that. I would like to keep it searching with regular expressions since it is fast. However, I have no idea how to set them up so it searches, and sorts, correctly. Any ideas, help, readings, or code would be appreciated.
Thanks
Use regex pattern
and group #1 of the match should be the number you use to compare strings at the first point.
If no numbers are found (no match), or same numbers are found, compare strings as text…