Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

May 4, 2010

Lambda Expressions: Zip

Filed under: C#,Lambda Expressions,VB.NET @ 11:33 pm

One of the new features in C# 4 and VB 10 (.NET 4.0) is the Zip extension method on IEnumerable. This method allows you to merge two lists such as two arrays or two generic List<T>.

The Zip extension method merges the two sequences by matching up each item in one sequence with another item in another sequence.

Starting with a simple example, say you have an array of numbers 0-5. And you also have an array of strings  that contain the number names zero-five. You want to merge these into a single array in the form: number (name), e.g. 0 (zero), 1 (one), and so on.

In C#:

int[] numberArray  = {0, 1, 2, 3, 4, 5};
string[] nameArray = {"zero", "one", "two",
                 "three", "four", "five"};

var combinedArray = numberArray.Zip(nameArray,
                    (number, name) => number.ToString() + " (" + 
                                      name + ")").ToArray();
Array.ForEach(combinedArray, s=> Console.WriteLine(s));

In VB:

Dim numberArray() As Integer = {0, 1, 2, 3, 4, 5}
Dim nameArray() As String = {"zero", "one", "two",
                             "three", "four", "five"}

Dim combinedArray = numberArray.Zip(nameArray,
                    Function(number, name) number.ToString & " (" & 
                                           name & ")").ToArray
Array.ForEach(combinedArray, Sub(s) Console.WriteLine(s))

The first two lines of code declare the two arrays: one with a set of numbers and the other with a set of names.

The Zip extension method combines the two arrays. Use the Zip method on either of the arrays and set the first parameter of the Zip method to the other array. The second parameter of the Zip method is a Lambda expression that details the desired result. In this case, the merged array contains a string concatenation of the number and name.

The parameters to the Lambda expression, number and name in this example, represent a value from each of the two arrays. The first parameter maps to the array defined to the left of the Zip method and the second parameter maps to the array defined as the first parameter to the Zip method.

(For more technical detail on how the Zip method works, see Bart De Smet’s blog post.)

The last line of code uses the ForEach extension method  to display each value in the merged array to the console.

The result is:

0 (zero)
1 (one)
2 (two)
3 (three)
4 (four)
5 (five)

Instead of returning a simple array, you can return an array of anonymous types. An anonymous type is like a class that you create dynamically that has no name, hence the reason it is called an anonymous type.

Using the same arrays as in the prior example, this next example returns an array of anonymous types where each item has a number and name.

In C#:

var nums = numberArray.Zip(nameArray,
    (number, name) => new { number, name});

foreach (var item in nums)
    Console.WriteLine(item);

In VB:

Dim nums = numberArray.Zip(nameArray,
        Function(number, name) New With {number, name})

For Each item In nums
    Console.WriteLine(item)
Next

This code starts with the same two arrays, but this time it creates an anonymous type. The new keyword defines the anonymous type and the list of items in the curly braces sets the properties of the anonymous type.

The result is:

{ number = 0, name = zero }
{ number = 1, name = one }
{ number = 2, name = two }
{ number = 3, name = three }
{ number = 4, name = four }
{ number = 5, name = five }

Now consider a more business-oriented example. Say you have a list of customers (like the one in this prior post) and a list of invoices (like the one in this prior post). You want to merge the lists into a single list so you can bind it to a grid.

In C#:

var listToBind = custList.Zip(invoiceList,
        (cust, inv) => new {
            LastName = cust.LastName,
            FirstName = cust.FirstName,
            InvoiceAmount = inv.InvoiceAmount,
            InvoiceDate = inv.InvoiceDate});
dataGridView1.DataSource = listToBind.ToList();

In VB:

Dim listToBind = custList.Zip(invoiceList,
                    Function(cust, inv) New With {
                        .LastName = cust.LastName,
                        .FirstName = cust.FirstName,
                        .InvoiceAmount = inv.InvoiceAmount,
                        .InvoiceDate = inv.InvoiceDate})
DataGridView1.DataSource = listToBind.ToList

This code uses the Zip extension method to combine the customer list and the invoice list. It uses the new keyword to create  an anonymous type with properties from both lists. The result can be bound to a grid, such as the DataGridView.

The result is as follows:

image

You can use filtering and sorting to change the contents of the resulting list. For example, the following code only displays invoices with amounts > 100.

In C#:

var listToBind = custList.Zip(invoiceList,
        (cust, inv) => new {
            LastName = cust.LastName,
            FirstName = cust.FirstName,
            InvoiceAmount = inv.InvoiceAmount,
            InvoiceDate = inv.InvoiceDate}).
            Where(c => c.InvoiceAmount>100);
dataGridView1.DataSource = listToBind.ToList();

In VB:

Dim listToBind = custList.Zip(invoiceList,
                    Function(cust, inv) New With {
                        .LastName = cust.LastName,
                        .FirstName = cust.FirstName,
                        .InvoiceAmount = inv.InvoiceAmount,
                        .InvoiceDate = inv.InvoiceDate}).
                        Where(Function(c) c.InvoiceAmount > 100)
DataGridView1.DataSource = listToBind.ToList

Use the Zip extension method any time you need to combine lists or build a new list from existing lists. This is especially useful for binding to grids.

Enjoy!

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2020 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs