1

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?

7 Answers 7

4

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

Sign up to request clarification or add additional context in comments.

Comments

4

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.

Comments

2

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

1 Comment

I prefer this approach when there is a chance that I'm going to need to sort in more than one way.
1

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

Comments

1

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.

Comments

0

Probably not the fastest way...

test = test.Where(x => x.StartsWith("_")).OrderByDescending(x => x).Concat(
       test.Where(x => !x.StartsWith("_")).OrderByDescending(x => x)).ToArray();

Comments

0

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.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.