3

I'm trying to implement the same example of this link but more oriented on the number of dependent kids.

http://www.codeproject.com/Articles/42839/Sorting-Lists-using-IComparable-and-IComparer-Inte

So I have 3 employees with A: 0, B: 0, C: 2 respectively. I want to order them descendently by number of kids. So I would have C:2, B:0, A:0

But my list it's not being sorted. It remains as A: 0, B: 0, C: 2

What I'm doing wrong?

My Comparer

public class EmployeeComparer : IComparer<Employee>
{
    public int Compare(Employee x, Employee y)
    {
        this.CompareNumberOfKids(x, y);
    }

    public int CompareNumberOfKids(Employee x, Employee y)
    {
        if (x.NumberOfKids > y.NumberOfKids)
        {
            return -1;
        }
        else if (x.NumberOfKids < y.NumberOfKids)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

My Business Entity

public class Employee : IComparable<Employee>
{
    //...//
    Public NumberOfKids { get; set; }

    int IComparable<Employee>.CompareTo(Employee next)
    {
        return new EmployeeComparer().Compare(this, next);
    }

    public override bool Equals(object obj)
    {
        if (obj != null && obj is Emmployee)
        {
            return ((Employee)obj).ID.Equals(this.ID);
        }
        else return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

Aspx.cs

public List<Employee> GetEmployeeSortedList()
{
    List<Employee> list = new List<Employee>();
    list.Add(new Employee() { Name = "A", NumberOfKids = 0 } );
    list.Add(new Employee() { Name = "B", NumberOfKids = 0 } );
    list.Add(new Employee() { Name = "C", NumberOfKids = 2 } );
    list.Add(new Employee() { Name = "D", NumberOfKids = 1 } );
    list.Add(new Employee() { Name = "E", NumberOfKids = 0 } );
    list.Add(new Employee() { Name = "F", NumberOfKids = 4 } );

    list = list.Take(3).ToList();
    EmployeeComparer comp = new EmployeeComparer();
    list.Sort(comp);
    return list;
}
Maximus Decimus
  • 4,901
  • 22
  • 67
  • 95
  • 2
    I just ran this code and it sorted it properly. Are you sure this is what you're doing? – Yuval Itzchakov Nov 11 '14 at 15:43
  • This code looks fine to me, though you don't need both an `IComparable` and `IComparer` The comparer is enough. Also, you can remove the `if` statements in favour of `x.NumberOfKids.CompareTo(y.NumberOfKids)` as the standard .NET types already implement `IComparable`. – Adam Houldsworth Nov 11 '14 at 15:53

2 Answers2

10

First, there's no need to have an IComparer<Employee> that sorts by descending if your Employee class implements IComparable<Employee> using the same sort criteria. And it's horribly inefficient for your Employee class to instantiate a new IComparer<Employee> for every comparision.

You should change your Employee class so that its CompareTo looks like this:

int CompareTo(Employee next)
{
    return next.NumberOfKids.CompareTo(this.NumberOfKids);
}

Then you can ditch the EmployeeComparer altogether and sort like this:

list = list.Take(3).ToList();
list.Sort();  // Uses default IComparable for the Employee class
return list;

Typically, you make the IComparable<T> implementation on the class perform the default sorting order. In the case of employees, that'd probably either be by employee ID or perhaps last name, first name. IComparer<T> implementations should be for other sorting criteria.

With List<T>, though, you have another option: use an anonymous function. For example, you could do this by writing:

list.Sort((x, y) => y.NumberOfKids.CompareTo(x.NumberOfKids));

See this List.Sort overload.

Or, you could just ditch the whole idea of IComparer<T> and IComparable<T> and List.Sort altogether and do it the LINQ way:

var result = list.Take(3).OrderByDescending(x => x.NumberOfKids).ToList();
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • The last line worked fine for me. But I implemented a new class IComparer in case of evaluating other alternatives more than NumberOfKids in a collection. Can I delegate the int CompareTo to a class that doesn't implements IComparer? – Maximus Decimus Nov 11 '14 at 16:12
  • @MaximusDecimus: I don't know what you mean by "delegate the int CompareTo". Take a look at http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=781 and http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=782, and http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=783. Perhaps those will shed some light on the subject. – Jim Mischel Nov 11 '14 at 16:31
  • As a sidenote, you can always get the `IComparer` of a type implementing `IComparable` using the static property `Comparer.Default`. – GregRos Nov 11 '14 at 20:03
2

here is another way got from msdn

using System;
using System.Collections;
namespace ConsoleEnum
{   
   public class car : IComparable
   {      
      // Beginning of nested classes.

      // Nested class to do ascending sort on year property.
      private class sortYearAscendingHelper: IComparer
      {
         int IComparer.Compare(object a, object b)
         {
            car c1=(car)a;
            car c2=(car)b;

            if (c1.year > c2.year)
               return 1;

            if (c1.year < c2.year)
               return -1;

            else
               return 0;
         }
      }

      // Nested class to do descending sort on year property.
      private class sortYearDescendingHelper: IComparer
      {
         int IComparer.Compare(object a, object b)
         {
            car c1=(car)a;
            car c2=(car)b;

            if (c1.year < c2.year)
               return 1;

            if (c1.year > c2.year)
               return -1;

            else
               return 0;
         }
      }

      // Nested class to do descending sort on make property.
      private class sortMakeDescendingHelper: IComparer
      {
         int IComparer.Compare(object a, object b)
         {
            car c1=(car)a;
            car c2=(car)b;
             return String.Compare(c2.make,c1.make);
         }
      }

      // End of nested classes.

      private int year;
      private string make;

      public car(string Make,int Year)
      {
         make=Make;
         year=Year;
      }

      public int Year
      {
         get  {return year;}
         set {year=value;}
      }

      public string Make
      {
         get {return make;}
         set {make=value;}
      }

      // Implement IComparable CompareTo to provide default sort order.
      int IComparable.CompareTo(object obj)
      {
         car c=(car)obj;
         return String.Compare(this.make,c.make);
      }

      // Method to return IComparer object for sort helper.
      public static IComparer sortYearAscending()
      {      
         return (IComparer) new sortYearAscendingHelper();
      }

      // Method to return IComparer object for sort helper.
      public static IComparer sortYearDescending()
      {      
         return (IComparer) new sortYearDescendingHelper();
      }

      // Method to return IComparer object for sort helper.
      public static IComparer sortMakeDescending()
      {      
        return (IComparer) new sortMakeDescendingHelper();
      }

   }
}

and here is how to use

using System;

namespace ConsoleEnum
{
   class host
   {
      [STAThread]
      static void Main(string[] args)
      {
         // Create an arary of car objects.      
         car[] arrayOfCars= new car[6]
         {
            new car("Ford",1992),
            new car("Fiat",1988),
            new car("Buick",1932),
            new car("Ford",1932),
            new car("Dodge",1999),
            new car("Honda",1977)
         };

         // Write out a header for the output.
         Console.WriteLine("Array - Unsorted\n");

         foreach(car c in arrayOfCars)
            Console.WriteLine(c.Make + "\t\t" + c.Year);

         // Demo IComparable by sorting array with "default" sort order.
         Array.Sort(arrayOfCars);
         Console.WriteLine("\nArray - Sorted by Make (Ascending - IComparable)\n");

         foreach(car c in arrayOfCars)
            Console.WriteLine(c.Make + "\t\t" + c.Year);

         // Demo ascending sort of numeric value with IComparer.
         Array.Sort(arrayOfCars,car.sortYearAscending());
         Console.WriteLine("\nArray - Sorted by Year (Ascending - IComparer)\n");

         foreach(car c in arrayOfCars)
            Console.WriteLine(c.Make + "\t\t" + c.Year);

         // Demo descending sort of string value with IComparer.
         Array.Sort(arrayOfCars,car.sortMakeDescending());
         Console.WriteLine("\nArray - Sorted by Make (Descending - IComparer)\n");

         foreach(car c in arrayOfCars)
            Console.WriteLine(c.Make + "\t\t" + c.Year);

         // Demo descending sort of numeric value using IComparer.
         Array.Sort(arrayOfCars,car.sortYearDescending());
         Console.WriteLine("\nArray - Sorted by Year (Descending - IComparer)\n");

         foreach(car c in arrayOfCars)
            Console.WriteLine(c.Make + "\t\t" + c.Year);

         Console.ReadLine();
      }
   }
}
Smith
  • 5,765
  • 17
  • 102
  • 161