You can build a comparator (IComparer
) which compares strings containing numbers, and passes it to the method OrderBy
:
lista.OrderBy(c => c.Str, meuComparador)
This comparator you can do using Regex.Split
to split the string at positions where numbers are found:
Regex.Split(str, @"(\d+)")
A regex \d+
serve to indicate that we want find strings with 1 or + digits:
\d
means any digit
+
means find one or more of the previous item
The parenthesis around the \d+
, serves to indicate to the split, that the number must be kept in the string breakdown array, so that we can use it in the comparison. See how it’s different:
Regex.Split("a123b", @"\d+") => array ["a", "b"]
Regex.Split("a123b", @"(\d+)") => array ["a", "123", "b"]
The string comparator class containing numbers
I implemented the class, to be present to those who need it in the future. = D
public class ComparerStringComNumeros : IComparer<string>
{
public static ComparerStringComNumeros Instancia
= new ComparerStringComNumeros();
private ComparerStringComNumeros() { }
public int Compare(string x, string y)
{
var itemsA = Regex.Split(x, @"(\d+)");
var itemsB = Regex.Split(y, @"(\d+)");
for (int it = 0; ; it++)
{
if (it == itemsA.Length)
return it == itemsB.Length ? 0 : -1;
if (it == itemsB.Length)
return 1;
if ((it % 2) == 0)
{
// parte não numérica
var strCompare = StringComparer.CurrentCulture.Compare(
itemsA[it],
itemsB[it]);
if (strCompare != 0)
return strCompare;
}
else
{
// parte numérica
var numCompare = Comparer<int>.Default.Compare(
int.Parse(itemsA[it]),
int.Parse(itemsB[it]));
if (numCompare != 0)
return numCompare;
}
}
}
}
Test the class above, using the OrderBy
:
public void TesteDeOrdenacao()
{
var l = new[]
{
"x0.2",
"m1.2",
"m1.04",
"m10.0",
"x1.2",
"x1.04",
"m10.0.0",
"x1.2.2",
"x1.04.8 a",
"x1.04.8 b",
"x1.04.8 c2",
"x1.04.8 c3",
"x1.04.8 c1",
"x10.0",
"m0.2"
};
var l2 = l.OrderBy(x => x, ComparerStringComNumeros.Instancia).ToList();
// l2 irá conter:
//
// "m0.2",
// "m1.2",
// "m1.04",
// "m10.0",
// "m10.0.0",
// "x0.2",
// "x1.2",
// "x1.2.2",
// "x1.04",
// "x1.04.8 a",
// "x1.04.8 b",
// "x1.04.8 c1",
// "x1.04.8 c2",
// "x1.04.8 c3",
// "x10.0"
}
How to use in your code:
var dirs = parentdir.GetDirectories()
.OrderBy(c => c.Name, ComparerStringComNumeros.Instancia)
.ToList();
Perfect guy, thank you very much. Looking at first I can not understand how you did it (even because I don’t know regex), but I will use this class to study.
– Jéf Bueno
I edited it! I added more information about regex, and how to interpret it.
– Miguel Angelo