Projection Operations
Projection refers to the operation of transforming an object into a new form that often consists only of those properties that will be subsequently used. By using projection, you can construct a new type that is built from each object. You can project a property and perform a mathematical function on it. You can also project the original object without changing it.
The standard query operator methods that perform projection are listed in the following section.
Methods
Method Name |
Description |
C# Query Expression Syntax |
Visual Basic Query Expression Syntax |
More Information |
---|---|---|---|---|
Select |
Projects values that are based on a transform function. |
select |
Select |
|
SelectMany |
Projects sequences of values that are based on a transform function and then flattens them into one sequence. |
Use multiple from clauses |
Use multiple From clauses |
Query Expression Syntax Examples
Select
The following example uses the select clause in C# or Select clause in Visual Basic to project the first letter from each string in a list of strings.
Dim words As New List(Of String)(New String() {"an", "apple", "a", "day"})
Dim query = From word In words _
Select word.Substring(0, 1)
Dim sb As New System.Text.StringBuilder()
For Each letter As String In query
sb.AppendLine(letter)
Next
' Display the output.
MsgBox(sb.ToString())
' This code produces the following output:
' a
' a
' a
' d
List<string> words = new List<string>() { "an", "apple", "a", "day" };
var query = from word in words
select word.Substring(0, 1);
foreach (string s in query)
Console.WriteLine(s);
/* This code produces the following output:
a
a
a
d
*/
SelectMany
The following example uses multiple from clauses in C# or From clauses in Visual Basic to project each word from each string in a list of strings.
Dim phrases As New List(Of String)(New String() {"an apple a day", "the quick brown fox"})
Dim query = From phrase In phrases _
From word In phrase.Split(" "c) _
Select word
Dim sb As New System.Text.StringBuilder()
For Each str As String In query
sb.AppendLine(str)
Next
' Display the output.
MsgBox(sb.ToString())
' This code produces the following output:
' an
' apple
' a
' day
' the
' quick
' brown
' fox
List<string> phrases = new List<string>() { "an apple a day", "the quick brown fox" };
var query = from phrase in phrases
from word in phrase.Split(' ')
select word;
foreach (string s in query)
Console.WriteLine(s);
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
Select versus SelectMany
The work of both Select() and SelectMany() is to produce a result value (or values) from source values. Select() produces one result value for every source value. The overall result is therefore a collection that has the same number of elements as the source collection. In contrast, SelectMany() produces a single overall result that contains concatenated sub-collections from each source value. The transform function that is passed as an argument to SelectMany() must return an enumerable sequence of values for each source value. These enumerable sequences are then concatenated by SelectMany() to create one large sequence.
The following two illustrations show the conceptual difference between the actions of these two methods. In each case, assume that the selector (transform) function selects the array of flowers from each source value.
This illustration depicts how Select() returns a collection that has the same number of elements as the source collection.
This illustration depicts how SelectMany() concatenates the intermediate sequence of arrays into one final result value that contains each value from each intermediate array.
Code Example
The following example compares the behavior of Select() and SelectMany(). The code creates a "bouquet" of flowers by taking the first two items from each list of flower names in the source collection. In this example, the "single value" that the transform function Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) uses is itself a collection of values. This requires the extra foreach (For Each in Visual Basic) loop in order to enumerate each string in each sub-sequence.
Class Bouquet
Public Flowers As List(Of String)
End Class
Sub SelectVsSelectMany()
Dim bouquets As New List(Of Bouquet)(New Bouquet() { _
New Bouquet With {.Flowers = New List(Of String)(New String() {"sunflower", "daisy", "daffodil", "larkspur"})}, _
New Bouquet With {.Flowers = New List(Of String)(New String() {"tulip", "rose", "orchid"})}, _
New Bouquet With {.Flowers = New List(Of String)(New String() {"gladiolis", "lily", "snapdragon", "aster", "protea"})}, _
New Bouquet With {.Flowers = New List(Of String)(New String() {"larkspur", "lilac", "iris", "dahlia"})}})
Dim output As New System.Text.StringBuilder
' Select()
Dim query1 = bouquets.Select(Function(b) b.Flowers)
output.AppendLine("Using Select():")
For Each flowerList In query1
For Each str As String In flowerList
output.AppendLine(str)
Next
Next
' SelectMany()
Dim query2 = bouquets.SelectMany(Function(b) b.Flowers)
output.AppendLine(vbCrLf & "Using SelectMany():")
For Each str As String In query2
output.AppendLine(str)
Next
' Display the output
MsgBox(output.ToString())
' This code produces the following output:
'
' Using Select():
' sunflower
' daisy
' daffodil
' larkspur
' tulip
' rose
' orchid
' gladiolis
' lily
' snapdragon
' aster
' protea
' larkspur
' lilac
' iris
' dahlia
' Using SelectMany()
' sunflower
' daisy
' daffodil
' larkspur
' tulip
' rose
' orchid
' gladiolis
' lily
' snapdragon
' aster
' protea
' larkspur
' lilac
' iris
' dahlia
End Sub
class Bouquet
{
public List<string> Flowers { get; set; }
}
static void SelectVsSelectMany()
{
List<Bouquet> bouquets = new List<Bouquet>() {
new Bouquet { Flowers = new List<string> { "sunflower", "daisy", "daffodil", "larkspur" }},
new Bouquet{ Flowers = new List<string> { "tulip", "rose", "orchid" }},
new Bouquet{ Flowers = new List<string> { "gladiolis", "lily", "snapdragon", "aster", "protea" }},
new Bouquet{ Flowers = new List<string> { "larkspur", "lilac", "iris", "dahlia" }}
};
// *********** Select ***********
IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
// ********* SelectMany *********
IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);
Console.WriteLine("Results by using Select():");
// Note the extra foreach loop here.
foreach (IEnumerable<String> collection in query1)
foreach (string item in collection)
Console.WriteLine(item);
Console.WriteLine("\nResults by using SelectMany():");
foreach (string item in query2)
Console.WriteLine(item);
/* This code produces the following output:
Results by using Select():
sunflower
daisy
daffodil
larkspur
tulip
rose
orchid
gladiolis
lily
snapdragon
aster
protea
larkspur
lilac
iris
dahlia
Results by using SelectMany():
sunflower
daisy
daffodil
larkspur
tulip
rose
orchid
gladiolis
lily
snapdragon
aster
protea
larkspur
lilac
iris
dahlia
*/
}
See Also
Tasks
How to: Combine Data with LINQ by Using Joins (Visual Basic)
How to: Populate Object Collections from Multiple Sources (LINQ)
How to: Return a LINQ Query Result as a Specific Type (Visual Basic)
How to: Split a File Into Many Files by Using Groups (LINQ)
Concepts
Standard Query Operators Overview