How to sort a list of objects by a specific field in C#?

I have this class:

public class StatInfo
{
  public string contact;
  public DateTime date;
  public string action;
}

then I have a list of StatInfo, but I'm not sure how to sort it according to the date field. Should I use the sort method? Should I create my own?

var _allStatInfo = new List<StatInfo>();
// adding lots of stuff in it
_allStatInfo.SortByDate???

What is the best way of doing this without having to write tons of code (if possible)?

Thanks


Solution 1:

Using LINQ:

var sortedList = _allStatInfo.OrderBy(si => si.date).ToList();

Sorting the original list:

_allStatInfo.Sort(new Comparison<StatInfo>((x, y) => DateTime.Compare(x.date, y.date)));

Solution 2:

I see you've got the answer anyway, but...

  1. You can avoid some ugliness by just splitting the statement into two halves:

    Comparison<StatInfo> comparison = (x, y) => DateTime.Compare(x.date, y.date);
    _allStatInfo.Sort(comparison);
    

    You might want to consider just calling CompareTo directly, too:

    Comparison<StatInfo> comparison = (x, y) => x.date.CompareTo(y.date);
    _allStatInfo.Sort(comparison);
    
  2. You could create an IComparer<T> implementation using my ProjectionComparer class - it's part of MiscUtil, and I've included an uncommented version at the bottom of this answer. You'd then write:

    _allStatInfo.Sort(ProjectionComparer<StatInfo>.Create(x => x.date));
    
  3. Even if you're using .NET 2.0, you can still use LINQ by way of LINQBridge.

Here's the ProjectionComparer class required for the second answer. The first couple of classes are really just helpers to let generic type inference work better.

public static class ProjectionComparer
{
    public static ProjectionComparer<TSource, TKey> Create<TSource, TKey>
        (Func<TSource, TKey> projection)
    {
        return new ProjectionComparer<TSource, TKey>(projection);
    }

    public static ProjectionComparer<TSource, TKey> Create<TSource, TKey>
        (TSource ignored, Func<TSource, TKey> projection)
    {
        return new ProjectionComparer<TSource, TKey>(projection);
    }

}

public static class ProjectionComparer<TSource>
{
    public static ProjectionComparer<TSource, TKey> Create<TKey>
        (Func<TSource, TKey> projection)
    {
        return new ProjectionComparer<TSource, TKey>(projection);
    }
}

public class ProjectionComparer<TSource, TKey> : IComparer<TSource>
{
    readonly Func<TSource, TKey> projection;
    readonly IComparer<TKey> comparer;

    public ProjectionComparer(Func<TSource, TKey> projection)
        : this (projection, null)
    {
    }

    public ProjectionComparer(Func<TSource, TKey> projection,
                              IComparer<TKey> comparer)
    {
        projection.ThrowIfNull("projection");
        this.comparer = comparer ?? Comparer<TKey>.Default;
        this.projection = projection;
    }

    public int Compare(TSource x, TSource y)
    {
        // Don't want to project from nullity
        if (x==null && y==null)
        {
            return 0;
        }
        if (x==null)
        {
            return -1;
        }
        if (y==null)
        {
            return 1;
        }
        return comparer.Compare(projection(x), projection(y));
    }
}

Solution 3:

To illustrate Robert C. Cartaino's answer:

public class StatInfo : IComparable<StatInfo>
{
    public string contact;
    public DateTime date;
    public string action;

    public int CompareTo(StatInfo value)
    {
        return this.date.CompareTo(value.date);
    }
}

var _allStatInfo = new List<StatInfo>();

// this now sorts by date
_allStatInfo.Sort();

Not the most general solution but good if you're only going to sort by date. And, as Robert said, you can still always override the default sort by passing an IComparer parameter to the sort method.

Solution 4:

Use a lambda expression to map a pair to a comparison:

_allStatInfo.Sort((x, y) => x.date - y.date);

Solution 5:

it worked for me ُSorting array of custom type using delegate

// sort array by name
Array.Sort(users, delegate(User user1, User user2) 
           {
             return user1.Name.CompareTo(user2.Name);
           });
// write array (output: Betty23 Lisa25 Susan20)
foreach (User user in users) Console.Write(user.Name + user.Age + " ");