프로젝션 작업
업데이트: 2007년 11월
프로젝션이란 개체를 다른 형태로 변환하는 작업을 가리키며, 대개는 나중에 사용될 속성만으로 구성되는 경우가 많습니다. 프로젝션을 사용하면 각 개체에서 빌드되는 새 형식을 구성할 수 있습니다. 속성을 프로젝션하여 해당 속성에 대한 수학 함수를 수행할 수 있습니다. 또한 원래 개체를 변경하지 않고 프로젝션할 수도 있습니다.
프로젝션을 수행하는 표준 쿼리 연산자 메서드는 다음 단원에 나열되어 있습니다.
메서드
메서드 이름 |
설명 |
C# 쿼리 식 구문 |
Visual Basic 쿼리 식 구문 |
추가 정보 |
---|---|---|---|---|
Select |
변환 함수에 따라 값을 프로젝션합니다. |
select |
Select |
|
SelectMany |
변환 함수에 기반하는 값 시퀀스를 프로젝션한 다음 하나의 시퀀스로 평면화합니다. |
여러 from 절 사용 |
여러 From 절 사용 |
쿼리 식 구문 예제
Select
다음 예제에서는 C#으로 작성된 select 절 또는 Visual Basic으로 Select 절을 사용하여 문자열 목록에서 각 문자열의 첫 번째 문자를 프로젝션합니다.
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
다음 예제에서는 C#으로 작성된 여러 from 절이나 Visual Basic으로 작성된 From 절을 사용하여 문자열 목록에서 각 문자열의 각 단어를 프로젝션합니다.
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와 SelectMany
Select() 및 **SelectMany()**의 역할은 모두 소스 값에서 결과 값을 생성하는 것입니다. **Select()**는 모든 소스 값에 대해 하나의 결과 값을 생성합니다. 따라서 전체 결과는 소스 컬렉션과 같은 수의 요소가 있는 컬렉션이 됩니다. 반대로 **SelectMany()**는 각 소스 값에서 연결된 하위 컬렉션을 포함하는 하나의 전체 결과를 생성합니다. **SelectMany()**에 인수로 전달되는 변환 함수는 각 소스 값에 대해 열거 가능한 값 시퀀스를 반환해야 합니다. 그러면 **SelectMany()**가 이러한 열거 가능한 시퀀스를 연결하여 하나의 큰 시퀀스를 만듭니다.
다음 두 그림에서는 이 두 메서드 작업의 개념적인 차이점을 보여 줍니다. 각 경우에 선택자(변환) 함수는 각 소스 값에서 꽃의 배열을 선택한다고 가정합니다.
이 그림에서는 **Select()**에서 소스 컬렉션과 동일한 수의 요소가 있는 컬렉션을 반환하는 방법을 설명합니다.
이 그림에서는 **SelectMany()**가 중간 배열 시퀀스를 각 중간 배열의 모든 값을 포함하는 하나의 최종 결과 값으로 연결하는 방법을 설명합니다.
코드 예제
다음 예제에서는 **Select()**와 **SelectMany()**의 동작을 비교합니다. 코드에서는 소스 컬렉션의 꽃 이름 목록 각각에서 첫 두 항목을 가져와 "부케"를 만듭니다. 이 예제에서 변환 함수 Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>)가 사용하는 "단일 값"은 그 자체가 값 컬렉션입니다. 이 예제에는 각 하위 시퀀스의 각 문자열을 열거하기 위해 추가적인 foreach(Visual Basic의 경우 For Each) 루프가 필요합니다.
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
*/
}