Bitwise Evolution

Musings of a Portland-area hacker bent on improving digital lifestyles.

(Not?) Ranting About .NET Collections...

The .NET collections continually frustrate me with the obvious ommisions, even in .NET 2.0. Coming from a Java / Lisp background, I really expect two things out of a data structures API:

  • Lots of collections to choose from.
  • and; Easy manipulation of the structures you have available.

.NET doesn’t fill either of these requirements very well. At least we have generics now (which, admittedly, is a step above what’s available in Lisp – with regard to types, anyway).

Today I ran into (yet another) annoyance with .NET collections – sorting arrays elegantly. Given an array, you can sort it in accending order (according to the default comparer) with Arrays.Sort(..).

// build & populate the array. 
double[] values = source.ToArray(); 

// destructively!! sorts values, returns void, of course.
Array.Sort(values); 

That’s nice. Now, sort it in reverse:

// build & populate the array. 
double[] values = source.ToArray(); 

Array.Sort(values); 
// reverse the array.. adds O(n) ops.
Array.Reverse(values);

or…

// build & populate the array. 
double[] values = source.ToArray(); 

Array.Sort(values, Double.ReverseComparer); 

Oh, wait. There is no ReverseComparer on Double.. actually, there’s no Comparer on Double either, but there is for most objects… so in general I could just wrap the comparer in a delegate or an anon class (to invert it) and use that.

Wait again.. c# doesn’t have anon classes, and Sort doesn’t take a delegate under any incantation. So, we could do this:

private class ReverseDoubleComparer : IComparer<double>{
    public int Compare(double x, double y){
        return y.CompareTo(x);
    }
}

/* 
intervening code...
*/
// build & populate the array. 
double[] values = source.ToArray(); 

Array.Sort(values, new ReverseDoubleComparer()); 

That will work, but wow… for every type, I’ll need to create a new class, and I can only deal with classes that implement IComparable.CompareTo(..). Thankfully, I can use generics and some constructor overloading to deal with both situations:

public class BackwardsComparer<T> : IComparer<T>{
   public BackwardsComparer(IComparer<T> c){
     _comparer = c;
   }

   public int Compare(T x, T y){
       return _comparer.Compare(y,x);
   }

   private IComparer<T> _comparer = null;
}

Now, we just need to do the following:

string[] strs = strSource.ToArray();

// sort strs in reverse alphabetical order:
Array.Sort(strs, 
   new BackwardsComparer<T>(StringComparer.CurrentCulture));

And there we have it – reverse array sorting without the additional cost of a Reverse() call, and avoiding the ugliness of case-specific classes floating around. (The complete listing for BackwardsComparer and test suite are here: BackwardsComparer.cs and BackwardsComparerTest.cs