Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a composite collection

So WPF doesn't support standard sorting or filtering behavior for views of CompositeCollections, so what would be a best practice for solving this problem.

There are two or more object collections of different types. You want to combine them into a single sortable and filterable collection (withing having to manually implement sort or filter).

One of the approaches I've considered is to create a new object collection with only a few core properties, including the ones that I would want the collection sorted on, and an object instance of each type.

class MyCompositeObject
{
    enum           ObjectType;
    DateTime       CreatedDate;
    string         SomeAttribute;
    myObjectType1  Obj1;
    myObjectType2  Obj2;
{
class MyCompositeObjects : List<MyCompositeObject> { }

And then loop through my two object collections to build the new composite collection. Obviously this is a bit of a brute force method, but it would work. I'd get all the default view sorting and filtering behavior on my new composite object collection, and I'd be able to put a data template on it to display my list items properly depending on which type is actually stored in that composite item.

What suggestions are there for doing this in a more elegant way?

like image 351
Christopher Scott Avatar asked Aug 14 '08 16:08

Christopher Scott


3 Answers

I'm not yet very familiar with WPF but I see this as a question about sorting and filtering List<T> collections.

(withing having to manually implement sort or filter)

Would you reconsider implementing your own sort or filter functions? In my experience it is easy to use. The examples below use an anonymous delegate but you could easily define your own method or a class to implement a complex sort or filter. Such a class could even have properties to configure and change the sort and filter dynamically.

Use List<T>.Sort(Comparison<T> comparison) with your custom compare function:

// Sort according to the value of SomeAttribute
List<MyCompositeObject> myList = ...;
myList.Sort(delegate(MyCompositeObject a, MyCompositeObject b) 
{
    // return -1 if a < b
    // return 0 if a == b
    // return 1 if a > b
    return a.SomeAttribute.CompareTo(b.SomeAttribute);
};

A similar approach for getting a sub-collection of items from the list.

Use List<T>.FindAll(Predicate<T> match) with your custom filter function:

// Select all objects where myObjectType1 and myObjectType2 are not null
myList.FindAll(delegate(MyCompositeObject a)
{
    // return true to include 'a' in the sub-collection
    return (a.myObjectType1 != null) && (a.myObjectType2 != null);
}
like image 184
Brian Ensink Avatar answered Nov 16 '22 18:11

Brian Ensink


"Brute force" method you mention is actually ideal solution. Mind you, all objects are in RAM, there is no I/O bottleneck, so you can pretty much sort and filter millions of objects in less than a second on any modern computer.

The most elegant way to work with collections is System.Linq namespace in .NET 3.5

Thanks - I also considered LINQ to objects, but my concern there is loss of flexibility for typed data templates, which I need to display the objects in my list.

If you can't predict at this moment how people will sort and filter your object collection, then you should look at System.Linq.Expressions namespace to build your lambda expressions on demand during runtime (first you let user to build expression, then compile, run and at the end you use reflection namespace to enumerate through results). It's more tricky to wrap your head around it but invaluable feature, probably (to me definitively) even more ground-breaking feature than LINQ itself.

like image 40
lubos hasko Avatar answered Nov 16 '22 19:11

lubos hasko


Update: I found a much more elegant solution:

class MyCompositeObject
{
    DateTime    CreatedDate;
    string      SomeAttribute;
    Object      Obj1;
{
class MyCompositeObjects : List<MyCompositeObject> { }

I found that due to reflection, the specific type stored in Obj1 is resolved at runtime and the type specific DataTemplate is applied as expected!

like image 33
Christopher Scott Avatar answered Nov 16 '22 18:11

Christopher Scott