We all had the issue with an OrderBy on a collection of String, having that kind of result:
Test1
Test10
Test2
Test20
Test3
Instead of:
Test1
Test2
Test3
Test10
Test20
Here is the solution:
public class NaturalComparer : Comparer<string>
{
public override int Compare(string x, string y)
{
if (x == y) return 0;
string[] x1, y1;
x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
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) && int.TryParse(right, out y))
return x.CompareTo(y);
return left.CompareTo(right);
}
}
public class ReverseNaturalComparer : NaturalComparer
{
public override int Compare(string x, string y)
{
return base.Compare(y, x);
}
}And this is how to use it:
[TestClass]
public class NaturalComparer_Test
{
public List<string> _unsortedCollection
{
get
{
var stringCollection = new List<string>();
stringCollection.Add("Test10");
stringCollection.Add("Test3");
stringCollection.Add("Test1");
stringCollection.Add("Test20");
stringCollection.Add("Test2");
return stringCollection;
}
private set { }
}
[TestMethod]
public void NaturalSort_Test()
{
var sortedCollection = _unsortedCollection
.OrderBy(x => x, new NaturalComparer())
.ToList();
Assert.IsNotNull(sortedCollection);
Assert.IsTrue(sortedCollection.Last() == "Test20");
}
[TestMethod]
public void ReversNaturalSort_Test()
{
var sortedCollection = _unsortedCollection
.OrderBy(x => x, new ReverseNaturalComparer())
.ToList();
Assert.IsNotNull(sortedCollection);
Assert.IsTrue(sortedCollection.Last() == "Test1");
}
}Happy coding! 😉




