Monday, March 21, 2011

How to sort List<T> using an Anonymous Method


Gottfried Wilhem Leibniz (from wikipedia)

This post illustrates how to use an anonymous method to perform “in line” sorting of a generic list. Let’s start with the definition of a “person” object.

public class Person  {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

And in our project we have created a generic list of “person” objects called “people”. The following code create the people variable and populates it with well known physicists.

// Create a list of people
List<Person> people = new List<Person>();
people.Add(new Person() { FirstName = "Gottfried", LastName = "Leibniz" });
people.Add(new Person() { FirstName = "Marie", LastName = "Curry" });
people.Add(new Person() { FirstName = "Albert", LastName = "Einsten" });
people.Add(new Person() { FirstName = "Isaac", LastName = "Newton" });
people.Add(new Person() { FirstName = "Niels", LastName = "Bohr" });

Next, let’s display the “before” list in a popup. This code uses a lambda expression in a LINQ expression to concatenate the names of our favorite physicists.

// Display "before" list of people
string before = string.Empty;
people.ForEach(
    new Action<Person>(
        p => before += string.Format(
            "{0} {1} {2}",
            p.FirstName,
            p.LastName,
            Environment.NewLine
        )
    )
);
MessageBox.Show(before);

image

Now, let’s sort the list of physicists based on their first name. This code block associates an anonymous method to the List’s Sort method.

// Sort on *FirstName*
people.Sort(
    delegate(Person x, Person y) {
        if (x == null) {
            if (y == null) { return 0; }
            return -1;
        }
        if (y == null) { return 0; }
        return x.FirstName.CompareTo(y.FirstName);
    }
);

To verify that the code worked…

// Display "after" list of people
string after = string.Empty;
people.ForEach(
    new Action<Person>(
        p => after += string.Format(
            "{0} {1} {2}",
            p.FirstName,
            p.LastName,
            Environment.NewLine
        )
    )
);
MessageBox.Show(after);

image

This technique offers a number of advantages, namely:

  • No need to create a separate static method,
  • Source types (eg “person”) do not need to support IComparable,
  • It binds sorting logic tightly with the sorting method.

One possible disadvantage is that it may result is code duplication. For example, if “sort by first name” is frequently used it may be prudent to add this code as a static method as shown below.

public class Person  {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public static int SortByFirstName(Person x, Person y){
        if (x == null) {
            if (y == null) { return 0; }
            return -1;
        }
        if (y == null) { return 0; }
        return x.FirstName.CompareTo(y.FirstName);
    }
}

This static method would then be referenced as shown below.

// Sort on *FirstName*
people.Sort(Person.SortFirstName);

1 comment: