Click here to Skip to main content
15,886,578 members
Articles / Desktop Programming / WPF

Dynamite: High Performace Dynamic Sorting Using Expressions

Rate me:
Please Sign up or sign in to vote.
4.89/5 (19 votes)
25 Sep 2008CPOL9 min read 86.7K   1K   61  
Easy-to-use and high performance dynamic sorting of most type of sequences with SQL-like syntax, developed using System.Linq.Expression classes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using Extensions;
using System.Text.RegularExpressions;
using System.Windows.Data;
using System.ComponentModel;
using Dynamite;
using Dynamite.Extensions;
using Dynamite.Data.Extensions;
using System.Collections;
using System.Data;
 
namespace DynamiteTester
{
    /// <summary>
    /// Interactive console test program for Dynamite dynamic sorting library
    /// </summary>
    class Program
    {
        public struct Point : IComparable
        {
            public int X { get; set; }
            public int Y { get; set; }
            public int? Height { get; set; }
            public Person Owner { get; set; }

            #region IComparable Members

            public int CompareTo(object obj)
            {
                if (obj == null) return -1;

                Point otherPoint = (Point)obj;
                return X.CompareTo(otherPoint.X);
            }

            #endregion

            public override string ToString()
            {
                return "{" + X + "," + Y + "}";
            }
        }

        public enum Sex
        {
            Male,
            Female
        }

        public class Person
        {
            public String Name { get; set; }
            public DateTime BirthDate { get; set; }
            public int Pets { get; set; }
            public Sex? Sex { get; set; }
            public Sex AttractedBy { get; set; }
            public DateTime? MarriedDate { get; set; }
            public Person Mother { get; set; }
            private Person Father;
            public bool IsMember;
            public Point? Coordinate { get; set; }
            public Point Point { get; set; }
        }

        static void Main(string[] args)
        {

           
            do
            {
                Console.WriteLine("Select comparison: ");
                Console.WriteLine("1=List<Person>.Sort((p1,p2) => String.Compare(p1.Name,p2.Name,...)");
                Console.WriteLine("2=List<Person>.Sort(ComparerBuilder<Person>.GetPropertyComparer(sortExpression, true)");
                Console.WriteLine("3=Reflection-Invoke-Based ");
                Console.WriteLine("4=List<Person>.Sort(sortExpression) using ComparerExtensions");
                Console.WriteLine("5=List<Person>.Sort using CreatePropertyComparer(sortExpression)");
                Console.WriteLine("6=List<Person>.Sort using.CreatePropertyComparerThroughEmit(sortExpression)");
                Console.WriteLine("7=List<Person>.AsQueryable().OrderBy(sortExpression)");
                Console.WriteLine("8=List<Person>.AsQueryable().OrderBy(p => p.Name)");
                Console.WriteLine("9=List<Person>.OrderBy(sortExpression)");
                Console.WriteLine("10=List<Person>.OrderBy(p => p.Name)");
                Console.WriteLine("11=CollectionViewSource.GetDefaultView(persons) sorting using SortDescription.");
                Console.WriteLine("12=CollectionViewSource.GetDefaultView(persons) sorting using CreateTypeComparer");
                Console.WriteLine("13=PersonDataTable.OrderBy(sortExpression)");
                Console.WriteLine("14=PersonDataTable.OrderBy(r => r.Name)");
                Console.WriteLine("15=PersonDataTable sorting using DataView.Sort=sortExpression");
                Console.WriteLine("Enter choice : ");

                String compType = Console.ReadLine();

                String sortExpression;

                Console.Write("Sort expression: ");
                sortExpression = Console.ReadLine();

                Console.Write("Count in each iteration (will be repeated until at least 100000 items have been sorted.) : ");
                int count = int.Parse(Console.ReadLine());


                Stopwatch watch = new Stopwatch();

                int totCount = 0;
                IEnumerator enumToVerify = null;

                while (totCount < 100000)
                {

                    List<Person> persons = new List<Person>(count);
                    Random rnd = new Random(12232322);
                    for (int i = 0; i < count; i++)
                    {
                        Person p = new Person()
                        {
                            Name = i % 50 == 0 ? null : (rnd.Next(2) == 0 ? "Person" : "person") + rnd.Next(count),
                            BirthDate = DateTime.Now.AddDays(-rnd.Next(36500)),
                            Pets = rnd.Next(4),
                            Sex = rnd.Next(3) == 0 ? Sex.Male : rnd.Next(2) == 0 ? Sex.Female : new Sex?(),
                            AttractedBy = rnd.Next(2) == 0 ? Sex.Male : Sex.Female,
                            MarriedDate = rnd.Next(100) > 0 ? new DateTime?(DateTime.Now.AddDays(-rnd.Next(36500))) : new DateTime?(),
                            Mother = i > 10 && rnd.Next(10) < 3 ? persons[rnd.Next(i)] : null,
                            Coordinate = rnd.Next(100) < 50 ? new Point() { X = rnd.Next(1000), Y = rnd.Next(1000) } : new Point?()
                        };
                        persons.Add(p);
                    }
                    PersonDataSet.PersonsDataTable personTable = new PersonDataSet.PersonsDataTable();
                    if (compType == "13" || compType == "14" || compType == "15" || compType == "16" || compType == "17")
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Person person = persons[i];
                            PersonDataSet.PersonsRow row = personTable.AddPersonsRow(i, person.Name, person.BirthDate, person.Pets, person.MarriedDate.HasValue ? person.MarriedDate.Value : DateTime.Now);
                            if (person.MarriedDate.HasValue == false) { row.SetMarriedDateNull(); }
                        }
                    }

                    enumToVerify = null;
                    watch.Start();
                    Comparison<Person> compName;
                    switch (compType)
                    {
                        case "2":
                            compName = ComparerBuilder<Person>.GetPropertyComparison(sortExpression, true);
                            persons.Sort(compName);
                            break;
                        case "3":
                            Extensions.Extensions.Sort(persons, sortExpression);
                            break;
                        case "4":

                            ComparerExtensions.Sort(persons, sortExpression);
                            break;
                        case "5":
                            Comparison<Person> c = ComparerBuilder<Person>.CreatePropertyComparison(sortExpression, true);
                            persons.Sort(c);
                            break;
                        case "6":
                            Comparison<Person> c2 = ComparerBuilder<Person>.CreatePropertyComparisonThroughEmit(sortExpression, true);
                            persons.Sort(c2);
                            break;
                        case "7":
                            persons = new List<Person>(persons.AsQueryable().OrderBy(sortExpression));
                            break;
                        case "8":
                            persons = new List<Person>(persons.AsQueryable().OrderBy(p => p.Name));
                            break;
                        case "9":
                            persons = new List<Person>(persons.OrderBy(sortExpression));
                            break;
                        case "10":
                            persons = new List<Person>(persons.OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase));
                            break;
                        case "11":

                            ICollectionView personView = CollectionViewSource.GetDefaultView(persons);
                            personView.SortDescriptions.Add(new SortDescription(sortExpression, ListSortDirection.Ascending));
                            enumToVerify = personView.GetEnumerator();
                            break;
                        case "12":
                            ListCollectionView personView2 = (ListCollectionView)CollectionViewSource.GetDefaultView(persons);

                            personView2.CustomSort = (System.Collections.IComparer)ComparerBuilder<Person>.CreateTypeComparer(sortExpression);
                            enumToVerify = ((ICollectionView)personView2).GetEnumerator();
                            break;
                        case "13":
                            var lastRow = personTable.AsEnumerable().OrderBy(sortExpression).Last();
                            enumToVerify = personTable.AsEnumerable().OrderBy(sortExpression).GetEnumerator();
                            break;
                        case "14":
                            var lastRow2 = personTable.AsEnumerable().OrderBy(r => r.Field<String>("Name"), StringComparer.CurrentCultureIgnoreCase).ThenBy(r => r.Field<int>("Pets")).Last();
                            enumToVerify = personTable.AsEnumerable().OrderBy(r => r.Field<String>("Name"), StringComparer.CurrentCultureIgnoreCase).ThenBy(r => r.Field<int>("Pets")).GetEnumerator();
                            break;
                        case "15":
                            var view = personTable.DefaultView;
                            view.Sort = sortExpression;
                            enumToVerify = view.GetEnumerator();
                            break;
                        /*
                        case "18":
                            Phydeaux.Utilities.DynamicComparer<Person> dynComparer = new Phydeaux.Utilities.DynamicComparer<Person>(sortExpression);
                            persons.Sort(dynComparer.Comparer);
                            break;
                         */
                        case "20":
                            persons = new List<Person>(persons.OrderBy(p => p.AttractedBy));
                            break;
                        case "21":
                            persons = new List<Person>(persons.OrderBy(p => (int)p.AttractedBy));
                            break;
                        default:
                            compName = (Person p1, Person p2) => String.Compare(p1.Name, p2.Name, StringComparison.CurrentCultureIgnoreCase);
                            //compName = (Person p1, Person p2) => Nullable.Compare(p1.Coordinate, p2.Coordinate);
                            //compName = (Person p1, Person p2) => p1.Sex.CompareTo(p2.Sex);
                            persons.Sort(compName);
                            break;
                    }
                    watch.Stop();
                    if (enumToVerify == null)
                    {
                        enumToVerify = persons.GetEnumerator();
                    }

                    totCount += count;

                }
                watch.Stop();
                Console.WriteLine("Time to sort {0} persons {1} times by {3}: {2} ms", count, totCount / count, watch.ElapsedMilliseconds, sortExpression);
                Console.WriteLine("Press ENTER to enumerate results. Enter q to quit enumeration.");
                while (Console.ReadLine() != "q")
                {
                    int i = 0;
                    while (i < 10 && enumToVerify.MoveNext())
                    {
                        if (enumToVerify.Current is Person)
                        {
                            Person p = (Person)enumToVerify.Current;
                            Console.WriteLine("{0} {1} {2} {3} {4} ({5})", p.Name, p.AttractedBy, p.BirthDate, p.MarriedDate, p.Coordinate, p.Mother == null ? "none" : p.Mother.Name);
                            i++;
                        }
                        else if (enumToVerify.Current is DataRow)
                        {
                            DataRow r = (DataRow)enumToVerify.Current;
                            Console.WriteLine("{0} {1} {2} {3}", r["Name"], r["Pets"], r["BirthDate"], r.Field<DateTime?>("MarriedDate"));
                            i++;
                        }
                        else if (enumToVerify.Current is DataRowView)
                        {
                            DataRow r = ((DataRowView)enumToVerify.Current).Row;
                            Console.WriteLine("{0} {1} {2} {3}", r["Name"], r["Pets"], r["BirthDate"], r.Field<DateTime?>("MarriedDate"));
                            i++;
                        }
                    }
                    Console.WriteLine("Press ENTER to show more results. Enter q to quit enumeration.");
                }
                Console.WriteLine("Press ENTER to go to main menu. Enter q to quit program. ");
            } while (Console.ReadLine() != "q");
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Sweden Sweden
Henrik Jonsson is a Microsoft Professional Certified Windows Developer (MCPD) that currently works as an IT consultant in Västerås, Sweden.

Henrik has worked in several small and large software development projects in various roles such as architect, developer, CM and tester.

He regularly reads The Code Project articles to keep updated about .NET development and get new ideas. He has contributed with articles presenting some useful libraries for Undo/Redo, Dynamic Linq Sorting and a Silverlight 5 MultiBinding solution.

Comments and Discussions