views:

337

answers:

3

Hi there,

Can anyone help.. I have a generic list like so

    IList<itemTp> itemTps;

itemTp basically is a class (has a number of properties) and one property on this is "code"

I need to be able to sort it an specific order which i have set in another List.

This list is a simple list that lists the order (starting from first to last) like say

code1 code3 code2 code5 (notice it goes from 1 to 3 to 2 to 5 - these are the names, they can be called anything .. the important thing is the order, it doesn't have anything to do with the numbers)

Basically i need ensure the items in itemTp sort according what is present in the other list...

So imagine my Ilist is like this code1,code2,code3,code5 - so once the sort is done in my

       IList<itemTp>

will contain 4 classes that are in order and have the property like code1,code3,code2,code5 (order change)

Any ideas how to do this?

A: 

Sorry if something is wrong, I don't have a C# editor installed here, but it's something like this:

 Array.Sort(
     itemTps, 
     delegate(ItemTp a, ItemTp b)
     {
          return secondList.IndexOf(a.Code) - secondList.IndexOf(b.Code);
     });

Note: it may not be the most efficient way, and also there is no checking whether the second list contains the Code at all.

[Edit] As Mehrdad said, Array.Sort doesn't work for generic IList<T>. To sort the array in place, you would need to use the ArrayList.Adapter method to create a wrapper, and then sort it. Since ArrayList.Sort doesn't support a delegate comparison, you need to put the anonymous delegate inside an implementation of IComparer<T>, .

If you need to sort it in a separate list, then it could have sense to use the logic above by creating an array first.

Groo
Array.Sort won't work on generic IList<T>
Mehrdad Afshari
Yep.. I was only thinking about the comparer. Here it is: http://stackoverflow.com/questions/15486/sorting-an-ilist-in-c
Groo
+4  A: 

You'll need to create an IComparer that will compare items based on the state of your other list. The advantage of using an IComparer is that you'll be able to build caching logic into your class to avoid repeated IndexOf() lookups if you need that optimization. Also, you'll be able to maintain multiple "other" lists that can be used when appropriate.

class ItemTpComparer : IComparer<itemTp>
{
    private IList<codeTp> otherList;

    public ItemTpComparer(IList<codeTp> otherList)
    {
        this.otherList = otherList;
    }

    public int Compare(itemTp a, itemTp b)
    {
        return otherList.IndexOf(a.Code) - otherList.IndexOf(b.Code);
    }
}

And to perform the sort:

myList.Sort(new ItemTpComparer(otherList));
anthony
I wouldn't say there is an advantage. You can pass the delegate to an instance method the same way you pass the interface, and have any logic you want in there.
Groo
this looks great, just one question, you are passing a and b into IndexOf on otherList ... so what would happen if i had "TestMeNow" and "TestMeLater" .. Indexof is going to return 6 for each one no??
mark smith
I don't understand your comment. If TestMeNow and TestMeLater are in other list, they both can't be at index 6.
anthony
@Groo: You can have any logic you want there, true, but you'd have to define a Dictionary outside your delegate block to hold cached values, etc. Defining an IComparer lets you encapsulate that logic into a class, and performing the sort will be one self contained line elsewhere in the code. Just a matter of preference.
anthony
By the way, the IList<T> interface doesn't have a Sort method. Not sure whether or not that's a problem: the question title says List<T> (which does have a Sort method) but the examples in the question use IList<T>.
LukeH
A: 

Using C# 3 and LINQ to Objects, I would just create a new list instead of trying to sort the existing one:

void Example()
{
    IList<string> codes;
    IList<ItemTp> itemTps;
    itemTps = codes.Select(code => itemTps.Single(itp => itp.Code == code)).ToList();
}
Per Erik Stendahl