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

4
  • 2
    (off-topic) Autoproperties anyone? Commented May 29, 2009 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) Commented May 29, 2009 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.. Commented May 29, 2009 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! Commented May 29, 2009 at 12:52

11 Answers 11

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));
Sign up to request clarification or add additional context in comments.

3 Comments

@Eoin: It's slightly ambiguous, I admit. I still believe he meant "Car Make Date" as one property, referring to CreationDate.
How to compare an int datatype through this method?
yeah i would like to know that too :) how do you compare an int datatype with this?
63

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);

4 Comments

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<T> 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. Yeah, your suggestion of using List.Sort(comparisson) could be quicker...
Thanks, I didn't know about ThenBy.
this is faster myList.Sort((x, y) => DateTime.Compare(x.Created, y.Created));
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.

1 Comment

+1 to counter the pointless -1 that someone else did. Nothing wrong with this suggestion.
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.

4 Comments

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 :-)
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 :)
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 you could create an extension method as discussed here: stackoverflow.com/questions/1827719/…
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.

1 Comment

This is a good solution if you don't have C# 3.0 available (i.e. no lambdas).
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; }
} 

Comments

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!

Comments

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...

Comments

1

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

Comments

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;
        });

    }

Comments

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));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.