40
public class CarSpecs
{
  public String CarName { get; set; }

  public String CarMaker { get; set; }

  public DateTime CreationDate { get; set; }
}

This is a list and I am trying to figure out an efficient way to sort this list List CarList, containing 6(or any integer amount) Cars, by the Car Make Date. I was going to do Bubble sort, but will that work? Any Help?

Thanks

bluish
  • 26,356
  • 27
  • 122
  • 180
  • 2
    (off-topic) Autoproperties anyone? – Peter Lillevold May 29 '09 at 11:33
  • 2
    @Peter Lillevold - that was my VERY FIRST THOUGHT too. I haven't written a "normal" property (backed by a local variable that I wrote) in a loooong time. (Just so mike knows: "public DateTime CreationDate { get; set; }" is legal in C# 3.0) – Mark Carpenter May 29 '09 at 11:39
  • 1
    Hm, i hit Alt-Enter in the editor to have ReSharper convert to autoproperty ... but nothing happened. ohwell, is it considered rude to edit code samples like this? though a bit risky in this instance since we're not sure if @Mike is using C# 3.0 or not.. – Peter Lillevold May 29 '09 at 11:55
  • @Peter - I'd probably just leave his code sample as-is (as the possibility still stands that he's not using 3.0). I suppose he can change it if he decides he wants to use automatic properties. I'll give you an "A" for effort, though! – Mark Carpenter May 29 '09 at 12:52

11 Answers11

94

The List<T> class makes this trivial for you, since it contains a Sort method. (It uses the QuickSort algorithm, not Bubble Sort, which is typically better anyway.) Even better, it has an overload that takes a Comparison<T> argument, which means you can pass a lambda expression and make things very simple indeed.

Try this:

CarList.Sort((x, y) => DateTime.Compare(x.CreationDate, y.CreationDate));
Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 1
    @Eoin: It's slightly ambiguous, I admit. I still believe he meant "Car Make Date" as one property, referring to `CreationDate`. – Noldorin May 29 '09 at 11:21
  • 1
    How to compare an int datatype through this method? –  Feb 16 '14 at 15:42
  • yeah i would like to know that too :) how do you compare an int datatype with this? – Dendei Jun 27 '14 at 07:47
62

You could use LINQ:

listOfCars.OrderBy(x => x.CreationDate);

EDIT: With this approach, its easy to add on more sort columns:

listOfCars.OrderBy(x => x.CreationDate).ThenBy(x => x.Make).ThenBy(x => x.Whatever);
Arjan Einbu
  • 13,543
  • 2
  • 56
  • 59
  • 4
    Yeah, this will do the job too. It will however have worse performance than using List.Sort, since it's based around LINQ (i.e. IEnumerable objects), though from the original question that wouldn't seem to be a big deal. The only real difference is that this returns a new object (which you then have to convert to a list using `ToList()`), whereas List.Sort performs the sort on the current instance. – Noldorin May 29 '09 at 11:17
  • @Noldorin. Yeah, your suggestion of using List.Sort(comparisson) could be quicker... – Arjan Einbu May 29 '09 at 11:21
  • Thanks, I didn't know about ThenBy. – Greg Fleming Jul 07 '11 at 15:56
  • 1
    this is faster myList.Sort((x, y) => DateTime.Compare(x.Created, y.Created)); – rochasdv Feb 27 '15 at 19:19
19

The best approach is to implement either IComparable or IComparable<T>, and then call List<T>.Sort(). This will do all the hard work of sorting for you.

Andy
  • 30,088
  • 6
  • 78
  • 89
14

Another option would be to use a custom comparer:

using System;
using System.Collections.Generic;
using System.Text;

namespace Yournamespace
{
   class CarNameComparer : IComparer<Car>
   {
      #region IComparer<Car> Members

      public int Compare(Car car1, Car car2)
      {
         int returnValue = 1;
         if (car1 != null && car2 == null)
         {
            returnValue = 0;
         }
         else if (car1 == null && car2 != null)
         {
            returnValue = 0;
         }
         else if (car1 != null && car2 != null)
         {
            if (car1.CreationDate.Equals(car2.CreationDate))
            {
               returnValue = car1.Name.CompareTo(car2.Name);
            }
            else
            {
               returnValue = car2.CreationDate.CompareTo(car1.CreationDate);
            }
         }
         return returnValue;
      }

      #endregion
   }
}

which you call like this:

yourCarlist.Sort(new CarNameComparer());

Note: I didn't compile this code so you might have to remove typo's

Edit: modified it so the comparer compares on creationdate as requested in question.

Peter
  • 14,221
  • 15
  • 70
  • 110
  • Modified my answer to match your comment. It is way to go to have full control over the sorting. But that may be too much in this case :-) – Peter May 29 '09 at 12:41
  • It's a good answer anyways since it is translatable to other languages as well. When you use linq or lambda expressions then you trap yourself in C#. _(although I'm very tempted no to do much right now and just use the 1 line of lambda :)_ – Bitterblue Jun 17 '14 at 11:30
  • I want to Use and implement IComparer Interface and DO NOT write "yourCarlist.Sort(new CarNameComparer());" . Just this : " yourCarlist.Sort(); " what should I do ??? I search all the stackoverflow :) – Parsa Feb 18 '17 at 19:16
  • 1
    @Parsa you could create an extension method as discussed here: http://stackoverflow.com/questions/1827719/c-sharp-sorting-using-extension-method – Peter Feb 21 '17 at 11:57
6

I would just use the build in List.Sort method. It uses the QuickSort algorithm which on average runs in O(n log n).

This code should work for you, I change your properties to auto-properties, and defined a static CompareCarSpecs method that just uses the already existing DateTime.CompareTo method.

class Program
{
    static void Main(string[] args)
    {
        List<CarSpecs> cars = new List<CarSpecs>();
        cars.Sort(CarSpecs.CompareCarSpecs);
    }
}

public class CarSpecs
{
    public string CarName { get; set; }
    public string CarMaker { get; set; }
    public DateTime CreationDate { get; set; }

    public static int CompareCarSpecs(CarSpecs x, CarSpecs y)
    {
        return x.CreationDate.CompareTo(y.CreationDate);
    }
}

Hope this helps.

Egil Hansen
  • 15,028
  • 8
  • 37
  • 54
3

Putting some of the pieces mentioned here together. This compiles and works in C# 4.x and VS2010. I tested with a WinForm. So add the method to the WinForm Main(). You will need the System.Linq and System.Generic.Collections assemblies at least.

    private void SortCars()
    {
        List<CarSpecs> cars = new List<CarSpecs>();
        List<CarSpecs> carsSorted = new List<CarSpecs>();

        cars.Add(new CarSpecs
        {
            CarName = "Y50",
            CarMaker = "Ford",
            CreationDate = new DateTime(2011, 4, 1),
        });

        cars.Add(new CarSpecs
        {
            CarName = "X25",
            CarMaker = "Volvo",
            CreationDate = new DateTime(2012, 3, 1),
        });

        cars.Add(new CarSpecs
        {
            CarName = "Z75",
            CarMaker = "Datsun",
            CreationDate = new DateTime(2010, 5, 1),
        });

        //More Comprehensive if needed  
        //cars.OrderBy(x => x.CreationDate).ThenBy(x => x.CarMaker).ThenBy(x => x.CarName);

        carsSorted.AddRange(cars.OrderBy(x => x.CreationDate));

        foreach (CarSpecs caritm in carsSorted)
        {
            MessageBox.Show("Name: " +caritm.CarName 
                + "\r\nMaker: " +caritm.CarMaker
                + "\r\nCreationDate: " +caritm.CreationDate);
        }
    }
}

public class CarSpecs
{
    public string CarName { get; set; }
    public string CarMaker { get; set; }
    public DateTime CreationDate { get; set; }
} 
Bob Kaufman
  • 12,864
  • 16
  • 78
  • 107
dpminusa
  • 327
  • 1
  • 7
1

If you're after an efficient way of sorting, I'd advise against using bubble sort and go for a quick sort instead. This page provides a rather good explanation of the algorithm:

http://www.devhood.com/Tutorials/tutorial_details.aspx?tutorial_id=574

Best of luck!

Mia Clarke
  • 8,134
  • 3
  • 49
  • 62
1

I would avoid writing my own sorting algorithm, but if you are going to anyway, have a look at http://www.sorting-algorithms.com/ for some comparrisons of different sorting algorithms...

Arjan Einbu
  • 13,543
  • 2
  • 56
  • 59
1

If you are using 2.0, the following discussion may be useful: C# List<> Sort by x then y

Community
  • 1
  • 1
Byron Ross
  • 1,595
  • 1
  • 14
  • 21
0

If you use delegates (also known as anonymous methods), you won't have to implement any IComparer / IComparable interfaces.

public static void Main(string[] args)
    {


      List<CarSpecs> list = new List<CarSpecs>();

      list.Add(new CarSpecs("Focus", "Ford", new DateTime(2010,1, 2));
      list.Add(new CarSpecs("Prius", "Toyota", new DateTime(2012,3, 3));
      list.Add(new CarSpecs("Ram", "Dodge", new DateTime(2013, 10, 6));



        list.Sort(delegate (CarSpecs first, CarSpecs second)
        {
            int returnValue = 1;
            if((first != null & second != null))
            {
                if (first.CarName.Equals(second.CarName))
                {
                    if (first.CarMaker.Equals(second.CarMaker))
                    {
                    returnValue = first.CreationDate.CompareTo(second.CreationDate);
                    }
                    else
                    {
                    returnValue = first.CarMaker.CompareTo(second.CarMaker);
                    }
                }
                else
                {
                    returnValue = first.CarName.CompareTo(second.CarName);
                }
            }
            return returnValue;
        });

    }
0

To extend the answer of Noldorin, in order to sort a list with int datatype this can be used:

listName.Sort((x, y) =>  x.CompareTo(y));

Or if you have a complex object in the list:

inventoryList.Sort((x, y) =>  x.stockNumber.CompareTo(y.stockNumber));
technoman
  • 26
  • 4