LP on .NET

February 11, 2011

Using LINQ to Create a Dictionary

Filed under: .NET,C#,Software Development — Larry Parker @ 10:22 pm

Often when I use LINQ to run a query against my data (whether objects, SQL or XML) I call .ToList() or .ToArray() at the end to execute the query and get a full in-memory representation of the result set.

Less frequently, but still useful at times, I will call .ToDictionary() to convert the collection into a Dictionary<TKey, TValue>.  For example, say we have a Customer class:

public class Customer
{
    public Int32 CustomerId { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

We could write a test like this:

[TestMethod]
public void DictionaryTest()
{
    Customer[] customers =
    {
        new Customer { CustomerId = 1001, FirstName = "Bill", LastName = "Smith" },
        new Customer { CustomerId = 1002, FirstName = "Mary", LastName = "Jones" },
        new Customer { CustomerId = 1003, FirstName = "Joe", LastName = "Thomas" }
    };

    Dictionary<Int32, Customer> dict = customers.ToDictionary<Customer, Int32>(o => o.CustomerId);
    Assert.AreEqual("Smith", dict[1001].LastName);
    Assert.AreEqual("Jones", dict[1002].LastName);
    Assert.AreEqual("Thomas", dict[1003].LastName);
}

The key of the dictionary is the customer ID (an integer), and each dictionary element contains the customer itself.  This is a great way to quickly convert a collection of elements into a keyed lookup that returns a particular object from a collection.

But what if we want our lookup to return something other than the full object?  Say we need to create a dictionary keyed by customer ID that returns the first and last name as a single string?

We could do something like this:

public Dictionary<Int32, String> GetCustomerDict(IEnumerable<Customer> customers)
{
    Dictionary<Int32, String> dict = new Dictionary<Int32, String>();

    foreach (Customer customer in customers)
        dict.Add(customer.CustomerId, customer.FirstName + " " + customer.LastName);

    return dict;
}

Then we could change our test like this:

[TestMethod]
public void DictionaryTest()
{
    Customer[] customers =
    {
        new Customer { CustomerId = 1001, FirstName = "Bill", LastName = "Smith" },
        new Customer { CustomerId = 1002, FirstName = "Mary", LastName = "Jones" },
        new Customer { CustomerId = 1003, FirstName = "Joe", LastName = "Thomas" }
    };

    Dictionary<Int32, String> dict = GetCustomerDict(customers);
    Assert.AreEqual("Bill Smith", dict[1001]);
    Assert.AreEqual("Mary Jones", dict[1002]);
    Assert.AreEqual("Joe Thomas", dict[1003]);
}

The key is still the customer ID, but instead of the dictionary element returning the full customer object, it now returns a simple string containing the customer’s first and last name.  Note also that the new dictionary has no reference to the original customer objects (which is sometimes desirable).

So our GetCustomerDict method works and was just a few lines of code.

But LINQ’s .ToDictionary extension method provides another overload that makes our lives much easier.  Here’s how it looks:

.ToDictionary<TSource, TKey, TElement>

Note that this overload take three types.  TSource is the type of our collection (Customer in this example), TKey is the type of the dictionary’s key (integer), and TElement is the type of the element we want to return (string in this case).  Just what we need!  🙂

Here’s the final version of the test:

[TestMethod]
public void DictionaryTest()
{
    Customer[] customers =
    {
        new Customer { CustomerId = 1001, FirstName = "Bill", LastName = "Smith" },
        new Customer { CustomerId = 1002, FirstName = "Mary", LastName = "Jones" },
        new Customer { CustomerId = 1003, FirstName = "Joe", LastName = "Thomas" }
    };

    Dictionary<Int32, String> dict = customers.ToDictionary<Customer, Int32, String>(k => k.CustomerId,
        e => e.FirstName + " " + e.LastName);

    Assert.AreEqual("Bill Smith", dict[1001]);
    Assert.AreEqual("Mary Jones", dict[1002]);
    Assert.AreEqual("Joe Thomas", dict[1003]);
}

One line of code does the trick.  The power of LINQ!  🙂

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: