Ian Boyd
Ian Boyd

Reputation: 256741

How to sort a Collection<T> in-place?

I have a generic collection:

public Items : Collection<Object>
{
   protected override void InsertItem(int index, Object item)
   {
      base.InsertItem(index, item);
      ...
   }

   protected override void RemoveItem(int index)
   {
      base.RemoveItem(index);
      ...
   }

   protected override void SetItem(int index, Object item)
   {
      base.SetItem(index, item);
      ...
   }

   protected override void ClearItems()
   {
      base.ClearItems();
      ...
   }

Now I need a way to sort this collection in-place.

Bonus Chatter

I tried converting my class to use List<T> rather than Collection<T> (since Collection<T> doesn't support the concept of an order). That then allowed calling the Sort method:

this.Items.Sort(SortCompareCallback);

protected virtual int SortCompareCallback(Object x, Object y)
{
   return OnCompareItems(new SortCompareEventArgs(x, y, this.sortColumnIndex, direction));
}

But then I lose the virtual methods when the list is modified.

I thought about using Linq, but the problem with that is:

How can I sort a generic Collection<T>?

Upvotes: 16

Views: 40533

Answers (6)

phoog
phoog

Reputation: 43046

If you don't need to have the virtual overrides called during the sorting, you should be able to do something like this:

class SortableCollection<T> : Collection<T>
{
    private readonly List<T> _list;

    public SortableCollection() : this(new List<T>()) {}
    public SortableCollection(List<T> list) : base(list)
    {
        _list = list;
    }
    public void Sort() { _list.Sort(); }
}

Or this:

class SortableCollection<T> : Collection<T>
{
    public SortableCollection() : this(new List<T>()) {}
    public SortableCollection(List<T> list) : base(list) {}
    public void Sort() { ((List<T>)Items).Sort(); }
}

Upvotes: 13

Dmitry Martynov
Dmitry Martynov

Reputation: 1

Use ArrayList.Adapter(yourCollection) and sort it as an array.

Upvotes: 0

Aditya
Aditya

Reputation: 89

Yes you can sort a collection try this:

public ICollection<T> getSortedData(ICollection<T> collection, string property, string direction)
{
    switch (direction.Trim())
    {
        case "asc":
            collection = ((from n in collection
                           orderby
                           n.GetType().GetProperty(property).GetValue(n, null)
                           select n).ToList<T>()) as ICollection<T>;
        break;
        case "desc":
            collection = ((from n in collection
                           orderby
                           n.GetType().GetProperty(property).GetValue(n, null)
                           descending
                           select n).ToList<T>()) as ICollection<T>;
        break;
    }
    return collection;
}

Upvotes: 1

zmbq
zmbq

Reputation: 39013

Collection<T> has an indexer. If you really want to sort the items in place, you can implement whatever sorting algorithm you prefer using the indexer. Here's an example that, with the proper Collection, can take O(N^3)...

void SortInPlace(Collection<T> col)
{
    for(int i=0; i<col.Count - 1; i++)
        for(int j=i+1; j<col.Count; j++)
            if(col[i] < col[j]) // This won't compile, but you get the jist
                Swap col[i] and col[j]
}

You can implement one of the O(NlogN) algorithms to get an O(N^2logN) sort performance if your collection only offers O(N) item access.

Upvotes: 2

Chris Shain
Chris Shain

Reputation: 51339

If you want a sortable list with content change notification, you should look at BindingList

Upvotes: 0

Eric J.
Eric J.

Reputation: 150108

You can use SortedList<T> (which also implements ICollection<T>, so you can treat it like a collection if you want to).

Upvotes: 1

Related Questions