Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / March 2008

Tip: Looking for answers? Try searching our database.

Generics & Sorting

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
TC - 25 Feb 2008 08:28 GMT
Hey All,

I've been handed a brain teaser of sorts and I'm hoping that you may be of
assistance.

Using a List or such of Generics objects, what would be the best way of
constructing one's own sorting algorithm?

For example, say we have class 'Dog' which has the properties 'Color', 'Age'
and 'Name'.  How would you go about building a generic sorting algorithm
such that one could sort by any of the above properties?

Please keep in mind that using .Net's native sorting method functions would
not be allowed.

I'm trying to think of a way to build a simple bubble sort but how to make
it transparent such that a consumer of the class or algorithm can specify
the sort key for the objects based upon the object's properties?

Thanks,

TC
Jon Skeet [C# MVP] - 25 Feb 2008 08:43 GMT
> I've been handed a brain teaser of sorts and I'm hoping that you may be of
> assistance.
[quoted text clipped - 8 lines]
> Please keep in mind that using .Net's native sorting method functions would
> not be allowed.

Actually *using* them shouldn't be allowed, but the design is all
there - you need some way to compare two objects, without knowing
their type beforehand. In other words, you need something to ask to
compare things: IComparer<T> and Comparison<T> spring to mind.

Jon
Marc Gravell - 25 Feb 2008 08:49 GMT
> Please keep in mind that using .Net's native sorting method functions would
> not be allowed.
Why not? Is this purely academic?

> I'm trying to think of a way to build a simple bubble sort but how to make
> it transparent such that a consumer of the class or algorithm can specify
> the sort key for the objects based upon the object's properties?

OK; what version of .NET do you have available? In .NET 3.5/C# 3, I
would be very tempted to look at using a lambda/delegate to specify
the property/properties - something similar to Jon's post here:
http://msmvps.com/blogs/jon.skeet/archive/2008/01/08/extension-methods-on-lamdba
-expressions-don-t-work-unfortunately.aspx


Re the fundamental ordering of values - look at IComparer<T>; as a
default, Comparer<TValue>.Default is a good bet, but it would be nice
to offer custom as an argument (see my reply to Jon's blog for an
illustration).

If you don't have .NET 3.5, then consider the approach that
IBindingListView adopts for ApplySort:
http://msdn2.microsoft.com/en-us/library/e6t44cba.aspx

It isn't quite as elegant to use, but suffices. I've posted examples
on writing sorted lists several times (to this forum), but always re-
using the standard sort functionality under the bonnet... so just add
your own "sort" implementation...

Marc
sloan - 25 Feb 2008 09:53 GMT
http://ludwig-stuyck.spaces.live.com/Blog/cns!E36D9BA98FC913B3!398.entry

Great C#/Generics article....in english.

And look at the ~~comments~~ of this blog entry:
http://sholliday.spaces.live.com/blog/cns!A68482B9628A842A!141.entry

> Hey All,
>
[quoted text clipped - 18 lines]
>
> TC
TC - 25 Feb 2008 10:44 GMT
Nice!

The best I was able to find was:

http://www.codeproject.com/KB/recipes/sortablecustomclass.aspx

Thanks!

That Ludwig stuff is great.

Best,

Todd

> http://ludwig-stuyck.spaces.live.com/Blog/cns!E36D9BA98FC913B3!398.entry
>
[quoted text clipped - 29 lines]
>>
>> TC
sloan - 25 Feb 2008 14:00 GMT
You need to be careful using Reflection to do sorting.

As the author points out......it becomes a little tedious to write
EmployeeComparer
DepartmentComparer
WorkWeekComparer
etc, etc.

However, if you're sorting a butt load (<<technical term) of records...you
may want to choose performance over ease.

> Nice!
>
[quoted text clipped - 44 lines]
>>>
>>> TC
TC - 25 Feb 2008 20:10 GMT
Yeah, the only problem with that is the fact that it is not loosely coupled
(i.e. we need a generic, no pun intended, comparer that can handle any
object for sorting).

For example:

   List<Person> AllPersons=new List<Person>();
   List<string> Properties=new List<string>();

   // We assume we pass the 3 values for the 'Person' properties
   Person Person1=new Person(12, "Smith", "Tom");
   AllPersons.Add(Person1);
   Person Person2=new Person(15, "Jones", "Davey");
   AllPersons.Add(Person2);

   GenericCompare<Person> SortIt=new GenericCompare<Person>();

   Properties.Add("Age");
   Properties.Add("LastName");
   // Sort list where first param is Generic list,
   // 2nd param are any number of properties in desired sort order,
   //3rd param is sort ascending
   SortIt(AllPersons, Properties, true);

Has anyone seen a sort algorithm for something like the above?

Regards,

Todd

> You need to be careful using Reflection to do sorting.
>
[quoted text clipped - 56 lines]
>>>>
>>>> TC
Kelly Herald - 25 Feb 2008 16:58 GMT
Take a look at the Dynamic Reflection Library from CodePlex.
http://www.codeplex.com/Dynamic

I use it in a few of my projects.

> Nice!
>
[quoted text clipped - 44 lines]
>>>
>>> TC
jay parzych - 26 Feb 2008 01:36 GMT
http://www.dotnet2themax.com/ShowContent.aspx?ID=05c3d0c3-ac44-4a20-92d9-16cdae040bc3

A universal comparer class
by Francesco Balena

The definitive comparer enables you to sort arrays and collections of
objects of any kind.

> Hey All,
>
[quoted text clipped - 18 lines]
>
> TC
TC - 26 Feb 2008 02:36 GMT
Sweet Jay!  Sweet, indeed!

;-)

Thanks for all of the help everyone.

By the way, apparently in 3.0, things get easier:

http://www.simple-talk.com/dotnet/.net-framework/.net-collection-management-with
-c-3.0/


> http://www.dotnet2themax.com/ShowContent.aspx?ID=05c3d0c3-ac44-4a20-92d9-16cdae040bc3
>
[quoted text clipped - 26 lines]
>>
>> TC
TC - 26 Feb 2008 03:09 GMT
Hey Jay,

The one problem, though, is that it doesn't use generics.  Do you have one
that does?

-- Todd

> http://www.dotnet2themax.com/ShowContent.aspx?ID=05c3d0c3-ac44-4a20-92d9-16cdae040bc3
>
[quoted text clipped - 26 lines]
>>
>> TC
TC - 02 Mar 2008 10:16 GMT
/// <summary>
       /// A generic bubblesort method implementation
       /// Bubblesort Explanation:  http://en.wikipedia.org/wiki/Bubblesort
       /// </summary>
       /// <typeparam name="T">The object type populating the
list</typeparam>
       /// <param name="sourceList">A list of objects</param>
       /// <param name="customComparer">A custom comparer object used to
compare the list items</param>
       public static void BubbleSort<T>(IList<T> sourceList, IComparer<T>
customComparer)
       {
           try
           {
               // Ensure that no null values have been provided
               if (sourceList == null)
               {
                   throw new ArgumentNullException("sourceList",
Properties.Resources.NullParam);
               }
               else if (customComparer == null)
               {
                   throw new ArgumentNullException("customComparer",
Properties.Resources.NullParam);
               }

               for (int counter = sourceList.Count - 1; counter >= 0;
counter--)
               {
                   // The inner loop ensures that all values are
re-compared and swapped, if necessary
                   for (int index = 1; index <= counter; index++)
                   {
                       if (customComparer.Compare(sourceList[index - 1],
sourceList[index]) > 0)
                       {
                           // Create a temporary holding object and swap
the order of the items
                           T tempListItem = sourceList[index - 1];
                           sourceList[index - 1] = sourceList[index];
                           sourceList[index] = tempListItem;
                       }
                   }
               }
           }
           catch (System.Exception exception)
           {
               ExceptionHandler.HandleException(exception);
           }
       }

       /// <summary>
       /// A generic quicksort method implementation
       /// </summary>
       /// <typeparam name="T">The object type populating the
list</typeparam>
       /// <param name="sourceList">A list of objects</param>
       /// <param name="customComparer">A custom comparer object used to
compare the list items</param>
       public static void QuickSort<T>(IList<T> sourceList, IComparer<T>
customComparer)
       {
           try
           {
               // Ensure that no null values have been provided
               if (sourceList == null)
               {
                   throw new ArgumentNullException("sourceList",
Properties.Resources.NullParam);
               }
               else if (customComparer == null)
               {
                   throw new ArgumentNullException("customComparer",
Properties.Resources.NullParam);
               }

               // Call the actual quicksort algorithm
               CustomObjectListSort.PrivateQuickSort(sourceList,
customComparer, 0, sourceList.Count - 1);
           }
           catch (System.Exception exception)
           {
               ExceptionHandler.HandleException(exception);
           }
       }
       #endregion

       #region Private Methods
       /// <summary>
       /// A generic quicksort algorithm implementation
       /// Quicksort Explanation:  http://en.wikipedia.org/wiki/Quicksort
       /// </summary>
       /// <typeparam name="T">The object type populating the
list</typeparam>
       /// <param name="sourceList">A list of objects</param>
       /// <param name="customComparer">A custom comparer object used to
compare the list items</param>
       /// <param name="lowIndex">Lower index in the list</param>
       /// <param name="highIndex">Upper index in the list</param>
       private static void PrivateQuickSort<T>(IList<T> sourceList,
IComparer<T> customComparer,int lowIndex, int highIndex)
       {
           try
           {
               // Ensure that no null values have been provided
               if (sourceList == null)
               {
                   throw new ArgumentNullException("sourceList",
Properties.Resources.NullParam);
               }
               else if (customComparer == null)
               {
                   throw new ArgumentNullException("customComparer",
Properties.Resources.NullParam);
               }

               int tempLowIndex = lowIndex + 1;
               int tempHighIndex = highIndex;

               // If the lowIndex is not less than the highIndex, the sort
is complete
               if (lowIndex < highIndex)
               {
                   // Create a temporary holding object for swapping the
order of the items
                   T tempListItem = sourceList[lowIndex];

                   // Loop through list until all items
                   // between indices have been compared
                   while (tempLowIndex < tempHighIndex)
                   {
                       // Keep incrementing temp indices until appropriate
discrepancy for swap is found
                       if (customComparer.Compare(sourceList[tempLowIndex],
tempListItem) <= 0)
                       {
                           tempLowIndex++;
                       }
                       else if
(customComparer.Compare(sourceList[tempHighIndex], tempListItem) >= 0)
                       {
                           tempHighIndex--;
                       }
                       else
                       {
                           tempListItem = sourceList[tempLowIndex];
                           sourceList[tempLowIndex] =
sourceList[tempHighIndex];
                           sourceList[tempHighIndex] = tempListItem;
                       }
                   }

                   if (customComparer.Compare(sourceList[tempLowIndex],
tempListItem) < 0)
                   {
                       // If tempLow is less than lowIndex, swap the items
                       tempListItem = sourceList[tempLowIndex];
                       sourceList[tempLowIndex] = sourceList[lowIndex];
                       sourceList[lowIndex] = tempListItem;
                       tempLowIndex--;
                   }
                   else
                   {
                       // Otherwise, swap item just below tempLow with the
lowIndex
                       tempLowIndex--;
                       tempListItem = sourceList[tempLowIndex];
                       sourceList[tempLowIndex] = sourceList[lowIndex];
                       sourceList[lowIndex] = tempListItem;
                   }

                   // Recursively call the quicksort function until both
partitions
                   // (i.e. 'lowIndex' and 'highIndex' pieces of list) are
complete
                   PrivateQuickSort(sourceList, customComparer, lowIndex,
tempLowIndex);
                   PrivateQuickSort(sourceList, customComparer,
tempHighIndex, highIndex);
               }
           }
           catch (System.Exception exception)
           {
               ExceptionHandler.HandleException(exception);
           }
       }

> Hey All,
>
[quoted text clipped - 18 lines]
>
> TC
Christopher Van Kirk - 03 Mar 2008 00:46 GMT
TC's implementation will work, but you have to provide a custom
comparer for the class. One alternative is to make your classes
inherit Comparable instead. The drawback of this approach is that you
can only sort in one order.

Your problem statement, however, implies that you want to be able to
sort by the properties intrinsically. TC's approach accomplishes this
by enabling you to design a custom comparer for any particular order
you like. An alternative is to have each of the "sortable" properties
inherit from IComparable or IComparable<>, and use reflection to
obtain handles to those properties. Reflection itself is quite slow,
but can be optimized as here: http://www.codeplex.com/Dynamic.

>        /// <summary>
>        /// A generic bubblesort method implementation
[quoted text clipped - 205 lines]
>>
>> TC

Signature

Posted via a free Usenet account from http://www.teranews.com

Jon Skeet [C# MVP] - 03 Mar 2008 07:47 GMT
> TC's implementation will work, but you have to provide a custom
> comparer for the class. One alternative is to make your classes
> inherit Comparable instead. The drawback of this approach is that you
> can only sort in one order.

If you specify Comparer<T>.Default, then if T implements IComparable it
will use that.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk


Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.