Array.Sort(test);
Comes out to be
_A
_B
_C
A
B
C
I reverse it
C
B
A
_C
.. You know
I want it to be
_C
_B
_A
C
B
A
So how could I do that?
If the built-in Array.Sort() does not sort the way you intend, you can override the IComparable.CompareTo method.
See this MSDN Article: How to: Sort Arrays Using Custom Criteria
Both the most efficient and simplest method would make use of the Comparison<T> delegate to do it all in one statement.
var items = new string[] { "_A", "_B", "_C", "A", "B", "C" };
Array.Sort(items, (a, b) =>
{
var aUnderscore = a.StartsWith("_");
var bUnderscore = b.StartsWith("_");
if (!(aUnderscore ^ bUnderscore))
return string.Compare(b, a);
else if (aUnderscore)
return -1;
else if (bUnderscore)
return +1;
return 0;
});
In uses lambda expressions, although not LINQ, so the performance hit should not be at all large, I believe.
You could create a comparer class that implements IComparer(Of String), then pass an instance of this class as the second parameter of Array.Sort.
Here's a sample code (in VB, sorry for that, but C# code would be similar):
Dim str = New String() {"_A", "_B", "_C", "A", "B", "C"}
Array.Sort(str, New SpecialComparer())
And here's my SpecialComparer:
Private Class SpecialComparer Implements IComparer(Of String)
Public Function Compare(ByVal x As String, ByVal y As String) As Integer
If x.StartsWith("_") And Not y.StartsWith("_") Then
Return -1
ElseIf y.StartsWith("_") And Not x.StartsWith("_") Then
Return 1
Else
Return y.CompareTo(x)
End If
End Function
End Class
You could implement your own Comparer like this:
public class MyOwnComparer: IComparer<string>
{
public int Compare(string x, string y)
{
if (x.StarsWith("_") && !y.StartsWith("_"))
return 1;
else if (!x.StartsWith("_") && y.StartsWith("_"))
return -1;
else
return x.CompareTo(y);
}
}
and then use it like this:
Array.Sort(test, new MyOwnComparer()); //sort ascending
var result = test.Reverse(); //now its descending
Read this article from MSDN about the Sort(Comparison) method, which includes a code example on how to write a custom sorter. I'd recommend copy/pasting it and tweaking it until you get what you're looking for.
Given your criteria I'd just do this (null or empty strings would cause a problem though):
List<string> items = new List<string>();
items.Sort();
List<string> result = items.FindAll(x => x[0] == '_');
result.AddRange(items.FindAll(x => x[0] != '_'));
A sort algorithm that doesn't compare all items may run into issues if you write a comparer that compares "_" strings from non-"_" strings. I recall having issues where the resulting order was incorrect because I wrote a comparer that did something similar.
Regardless, a custom comparer:
List<string> items = new List<string>();
items.Sort(
delegate(string a, string b)
{
if (a[0] == '_' && b[0] == '_')
{
return -a.CompareTo(b);
}
else if (a[0] == '_')
{
return 1;
}
else if (b[0] == '_')
{
return -1;
}
else
{
return a.CompareTo(b);
}
}
);
I also find the former to be more readable, but YMMV. (Note the minus signs to reverse sort.)