BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

LINQ
.NET 3.5+

LINQ Conversion

The thirteenth part of the LINQ to Objects tutorial describes some of the conversion operators provided by Language-Integrated Query (LINQ). These operators allow you to convert between sequence types or cast the elements of a sequence to another type.

Conversion

Language-Integrated Query (LINQ) provides several standard query operators that allow a sequence of items to be converted in some manner. These operators can be broadly categorised into two groups. The first group is used to convert an entire sequence into another type of collection without changing the types of the individual items. The second style of operator converts a collection into a sequence that implements the IEnumerable<T> interface at the same time as changing the underlying types of the individual items.

In this article we will look at the most common standard query operators for both types of conversion. Some conversion operators will be omitted from this tutorial and will be described in future articles. This article will not use query expression syntax as all conversion is achieved using standard query operators. No special query clauses are available for conversion but the operators may be applied to the results of a query.

Converting Enumerables to Other Types

We will begin by looking at the extension methods that convert an entire sequence from one type of collection to another, whilst leaving the contents unchanged. For simplicity we will use sample data that contains only basic types. However, there is no reason why more complex classes or structures cannot be used.

The sample data for this section is defined using the following code:

int[] array = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
List<int> list = new List<int> { 1, 4, 9, 16, 25, 36, 49, 64 };

ToArray

The first of the conversion operators is ToArray. As the name suggests, this method extracts all of the items from the source sequence and returns a new array containing those items. Unlike many standard query operators, this method does not use deferred execution. If used against the results of a query, the query will be immediately executed and the results copied into the new array. This can be useful when you want to ensure that a query is executed before other code has the opportunity to change the data source, or when you wish to generate a cached copy of a data set.

The following sample code creates an array containing the eight items from the list.

int[] converted = list.ToArray();

ToList

The ToList method is similar to ToArray in operation. The key difference is that the return value is a generic List<T> collection containing the items from the source sequence. This can be seen by executing the following example, which creates a list of integers containing the ten items from the sample array.

List<int> converted = array.ToList();

ToDictionary

The third of the conversion operators is ToDictionary. This method is similar to ToArray and ToList, in that it immediately generates a new collection holding data from the source collection. In this case, the returned collection is a Dictionary that contains a single key / value pair for each element in the source data.

The simplest version of the ToDictionary method accepts a single argument that defines a key selector. This is a Func delegate, usually expressed as a lambda, that generates a key based upon each element of the source collection. This is paired with the original value and added to the new dictionary. The method of generation for the key selector must be carefully considered to ensure that all of the keys are unique. If two identical keys are created the operation will fail.

The sample data in the generic list contains the squares of the integers between one and eight. We can use this knowledge to generate keys that are the square root of those values. This is shown in the code below, which uses the Math.Sqrt method to generate a key for each value. The key / value pairs are shown in the comment beneath the call to ToDictionary.

Dictionary<int, int> converted = list.ToDictionary(i => (int)Math.Sqrt(i));

/* RESULTS

(1, 1)
(2, 4)
(3, 9)
(4, 16)
(5, 25)
(6, 36)
(7, 49)
(8, 64)

*/

A second overloaded version of ToDictionary allows you to provide a key selector and an element selector. As in the previous example, the key selector is a delegate that generates the key for each of the items in the new dictionary. The element selector is a second delegate that generates the matching value for the key. This is useful when working with classes with many properties. In such situations you may wish to extract two of those properties to use as the key and value in each result.

The code below shows the use of an element selector. This sample creates a dictionary where the key is the square root of the original value and the value is ten times the original integer.

Dictionary<int, int> converted = list.ToDictionary(
    key => (int)Math.Sqrt(key), element => element * 10);
    
/* RESULTS

(1, 10)
(2, 40)
(3, 90)
(4, 160)
(5, 250)
(6, 360)
(7, 490)
(8, 640)

*/

NB: Two further overloaded versions of ToDictionary exist. Each adds an IEqualityComparer<T> parameter that is used by the dictionary to determine whether two keys match.

27 September 2010