views:

18525

answers:

13

So I came across an interesting problem today. We have a WCF web service that returns an IList. Not really a big deal until I wanted to sort it.

Turns out the IList interface doesn't have a sort method built in.

I ended up using the ArrayList.Adapter(list).Sort(new MyComparer()) method to solve the problem but it just seemed a bit "ghetto" to me.

I toyed with writing an extension method, also with inheriting from IList and implementing my own Sort() method as well as casting to a List but none of these seemed overly elegant.

So my question is, does anyone have an elegant solution to sorting an IList

+7  A: 

You're going to have to do something like that i think (convert it into a more concrete type).

Maybe take it into a List of T rather than ArrayList, so that you get type safety and more options for how you implement the comparer.

Leon Bambrick
+2  A: 

Convert your IList into List<T> or some other generic collection and then you can easily query/sort it using System.Linq namespace (it will supply bunch of extension methods)

lubos hasko
`IList<T>` implements `IEnumerable<T>` and therefore doesn't need to be converted to use Linq operations.
Steve Guidi
+18  A: 

How about using LINQ To Objects to sort for you?

Say you have a IList<Car>, and the car had an Engine property, I believe you could sort as follows:

from c in list
orderby c.Engine
select c;

Edit: You do need to be quick to get answers in here. As I presented a slightly different syntax to the other answers, I will leave my answer - however, the other answers presented are equally valid.

Brad Leach
+13  A: 

You can use LINQ:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
Mark Cidade
A: 

I'm going with secretgeek on this one. Whilst I like the linq implementations, they do limit things to people with access to C# 3.x.

lomaxx
A: 

@brad: you sure do, but the answer you posted is still valid as it offers a solution to a slightly different problem to the one that marxidad posted.

On a side note, if I could accept partial answers, I would have given partial credits to all of the answers provided.

lomaxx
+1  A: 

@lomaxx Well, there is LINQBridge

Mark Cidade
A: 

Here's an example using the stronger typing. Not sure if it's necessarily the best way though.

static void Main(string[] args)
{
    IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
    List<int> stronglyTypedList = new List<int>(Cast<int>(list));
    stronglyTypedList.Sort();
}

private static IEnumerable<T> Cast<T>(IEnumerable list)
{
    foreach (T item in list)
    {
        yield return item;
    }
}

The Cast function is just a reimplementation of the extension method that comes with 3.5 written as a normal static method. It is quite ugly and verbose unfortunately.

ICR
A: 

In VS2008, when I click on the service reference and select "Configure Service Reference", there is an option to choose how the client de-serializes lists returned from the service.

Notably, I can choose between System.Array, System.Collections.ArrayList and System.Collections.Generic.List

David B
A: 

Found a good post on this and thought I'd share. Check it out HERE

Basically.

You can create the following class and IComparer Classes

public class Widget {
    public string Name = string.Empty;
    public int Size = 0;

    public Widget(string name, int size) {
    this.Name = name;
    this.Size = size;
}
}

public class WidgetNameSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
        return x.Name.CompareTo(y.Name);
}
}

public class WidgetSizeSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
    return x.Size.CompareTo(y.Size);
}
}

Then If you have an IList, you can sort it like this.

List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget("Zeta", 6));
widgets.Add(new Widget("Beta", 3));
widgets.Add(new Widget("Alpha", 9));

widgets.Sort(new WidgetNameSorter());
widgets.Sort(new WidgetSizeSorter());

But Checkout this site for more information... Check it out HERE

A: 
using System.Linq;

var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );

That's pretty !ghetto.

+1  A: 

Found this thread while I was looking for a solution to the exact problem described in the original post. None of the answers met my situation entirely, however. Brody's answer was pretty close. Here is my situation and solution I found to it.

I have two ILists of the same type returned by NHibernate and have emerged the two IList into one, hence the need for sorting.

Like Brody said I implemented an ICompare on the object (ReportFormat) which is the type of my IList:

 public class FormatCcdeSorter:IComparer<ReportFormat>
    {
       public int Compare(ReportFormat x, ReportFormat y)
        {
           return x.FormatCode.CompareTo(y.FormatCode);
        }
    }

I then convert the merged IList to an array of the same type:

ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList

Then sort the array:

Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer

Since one-dimensional array implements the interface System.Collections.Generic.IList<T>, the array can be used just like the original IList.

John
this is the correct way to do this.
Sem Dendoncker
+1  A: 

Is this a valid solution?

        IList<string> ilist = new List<string>();
        ilist.Add("B");
        ilist.Add("A");
        ilist.Add("C");

        Console.WriteLine("IList");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

        List<string> list = (List<string>)ilist;
        list.Sort();
        Console.WriteLine("List");
        foreach (string val in list)
            Console.WriteLine(val);
        Console.WriteLine();

        list = null;

        Console.WriteLine("IList again");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

The result was: IList B A C

List A B C

IList again A B C