Showing posts with label Linq. Show all posts
Showing posts with label Linq. Show all posts

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

Friday, March 19, 2010

How to sort an ObservableCollection

ObservableCollection<T> is frequently used in Silverlight and WPF applications as a bindable data source to elements like ListBoxes and TreeViews.  This is because the collection supports INotifyPropertyChanged, an interface that is referenced by hosts elements so they can be notified whenever the collection changes.

Unlike List<T> and other collection types, ObservableCollection<T> does not natively support sorting.  This post will explore three options for sorting an ObservableCollection.

To start, let’s define Person, a class that supports IComparable, an interface that instructs other objects how to rank person objects.

public class Person : IComparable {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int CompareTo(object obj) {
        Person person = obj as Person;
        if (person == null) {
            throw new ArgumentException("Object is not Preson");
        }
        return this.LastName.CompareTo(person.LastName);
    }
}

Next, create a collection of Persons using ObservableCollection<Person> and populate with some well known physicists.

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

The first techniques uses the OrderBy LINQ extension with a simple lambda expression.

ObservableCollection<Person> peopleSort = new ObservableCollection<Person>(
    people.OrderBy(person => person)
);

The disadvantage of this method is that a new collection is created.  Transferring items from the sorted collection to the original collection could be expensive.  The advantage however is that lambda expressions provide almost unlimited flexibility with respect to defining the sorting logic.  By default, Person objects are sorted by the LastName property as defined in its implementation of IComparable.  However to sort by FirstName we can use the following:

ObservableCollection<Person> peopleSort = new ObservableCollection<Person>(
    people.OrderBy(person => person.FirstName)
);

A second method of sorting is to make use of the existing Sort method in List<T>.

List<Person> list = new List<Person>(people);
list.Sort();

But once again, to use this method the end result is the creation of two collections.

Lastly, I would like to describe a third option for sorting ObservableCollection<T> that makes use of the custom LINQ extension as defined below.  The expression performs a bubble sort with the assumption that the items in the generic collection support IComparable.

public static class ListExtension {
    public static void BubbleSort(this IList o) {
        for (int i = o.Count - 1; i >= 0; i--) {
            for (int j = 1; j <= i; j++) {
                object o1 = o[j - 1];
                object o2 = o[j];
                if (((IComparable)o1).CompareTo(o2) > 0) {
                    o.Remove(o1);
                    o.Insert(j, o1);
                }
            }
        }
    }
}

To sort ObservableCollection<Persons> we just need the following statement.

people.BubbleSort();

In summary, I have described three methods of sorting a ObservableCollection<T>.  The first used a List<T>, the second the OrderBy LINQ extension and the last method defined a custom bubble sort LINQ extension.  Each method has its advantages and disadvantages and I am sure are more methods too.  Please feel free to comment if you would like to suggest additional methods.

Wednesday, December 16, 2009

Twitter & ESRI’s Silverlight API

Twitter & ESRI's Silverlight API

Ever wonders what people are talking about at a particular location?  This application, developed by the ESRI’s Applications Prototype Lab, uses Twitter’s search API and ESRI’s Silverlight API to request and display geo-referenced tweets.  The application is accessible from the following link.
http://maps.esri.com/sldemos/twittermap/default.aspx

To use, first zoom into an area of interest (preferably an urban area).  Click the Add button in the upper left hand corner of the application and then click once on the map.  The ten most recent tweets within the search radius will be added to the map using the tweeter’s profile image.  Mouse-over the profile images to read the tweets themselves.  Next, try refining your search with a smaller (or larger) search radius and the inclusion of a search keyword like #esri.

The following technologies were used to develop this application:

  1. Microsoft Silverlight 3
    http://silverlight.net/
  2. ESRI’s ArcGIS API for Silverlight version 1.1
    http://resources.esri.com/arcgisserver/apis/silverlight/
  3. Microsoft Silverlight Toolkit (November 2009)
    http://www.codeplex.com/Silverlight
  4. Linq to Twitter
    Comprehensive LINQ provider to Twitter’s API
    http://linqtotwitter.codeplex.com/
  5. Orbifold’s Graphite for Silverlight
    Simple framework for presenting spring-enabled node-edge diagrams.
    http://www.orbifold.net/default/?page_id=1270