연습: C#에서 쿼리 작성(LINQ)
이 연습에서는 LINQ 쿼리 식을 작성하는 데 사용되는 C # 언어 기능을 보여 줍니다.
C# 프로젝트 만들기
참고
다음 지침은 Visual Studio용입니다. 다른 개발 환경을 사용하는 경우 System.Core.dll에 대한 참조와 System.Linq 네임스페이스에 대한 using
지시문을 사용하여 콘솔 프로젝트를 만듭니다.
Visual Studio에서 프로젝트를 만들려면
Visual Studio를 시작합니다.
메뉴 모음에서 파일, 새로 만들기, 프로젝트를 차례로 선택합니다.
새 프로젝트 대화 상자가 열립니다.
설치됨, 템플릿, Visual C# 을 차례로 확장하고 콘솔 애플리케이션을 선택합니다.
이름 텍스트 상자에 다른 이름을 입력하거나 기본 이름을 선택한 다음 확인 단추를 선택합니다.
솔루션 탐색기에 새 프로젝트가 표시됩니다.
프로젝트에 System.Core.dll에 대한 참조 및 System.Linq 네임스페이스에 대한
using
지시문이 있습니다.
메모리 내 데이터 소스 만들기
쿼리의 데이터 소스는 간단한 Student
개체 목록입니다. 각 Student
레코드에는 이름, 성 및 클래스의 테스트 점수를 나타내는 정수 배열이 있습니다. 프로젝트에 이 코드를 복사합니다. 다음 특성에 주의합니다.
Student
클래스는 자동으로 구현된 속성으로 구성됩니다.목록의 각 학생은 개체 이니셜라이저로 초기화됩니다.
목록 자체는 컬렉션 이니셜라이저로 초기화됩니다.
이 전체 데이터 구조는 생성자 또는 명시적 멤버 액세스에 대한 명시적 호출 없이 초기화되고 인스턴스화됩니다. 이러한 새로운 기능에 대한 자세한 내용은 자동으로 구현된 속성 및 개체 및 컬렉션 이니셜라이저를 참조하세요.
데이터 소스를 추가하려면
Student
클래스 및 초기화된 학생 목록을 프로젝트의Program
클래스에 추가합니다.public class Student { public string First { get; set; } public string Last { get; set; } public int ID { get; set; } public List<int> Scores; } // Create a data source by using a collection initializer. static List<Student> students = new List<Student> { new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}}, new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}}, new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}}, new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}}, new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}}, new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}}, new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}}, new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}}, new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}}, new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}}, new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}}, new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}} };
학생 목록에 새 학생을 추가하려면
- 새
Student
를Students
목록에 추가하고 원하는 이름 및 시험 점수를 사용합니다. 개체 이니셜라이저의 구문을 더 잘 알 수 있도록 새로운 학생 정보를 모두 입력해 보세요.
쿼리 만들기
단순 쿼리를 작성하려면
애플리케이션의
Main
메서드에서, 실행 시 첫 번째 테스트의 점수가 90보다 큰 모든 학생의 목록을 생성하는 간단한 쿼리를 만듭니다. 전체Student
개체가 선택되므로 쿼리의 형식은IEnumerable<Student>
입니다. var 키워드를 사용하여 코드에서 암시적 형식을 사용할 수도 있지만, 결과를 명확하게 설명하기 위해 명시적 형식이 사용됩니다.var
에 대한 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.또한 쿼리의 범위 변수
student
는 소스의 각Student
에 대한 참조로 사용되며, 각 개체에 대한 멤버 액세스를 제공합니다.
// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
from student in students
where student.Scores[0] > 90
select student;
쿼리 실행
쿼리를 실행하려면
이제 쿼리를 실행하도록 할
foreach
루프를 작성합니다. 다음은 코드에 대한 유의 사항입니다.반환된 시퀀스의 각 요소는
foreach
루프의 반복 변수를 통해 액세스됩니다.이 변수의 형식은
Student
이며, 쿼리 변수 형식은IEnumerable<Student>
과 호환됩니다.
이 코드를 추가한 후 애플리케이션을 빌드하고 실행하고 콘솔 창에서 결과를 확인하세요.
// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
Console.WriteLine("{0}, {1}", student.Last, student.First);
}
// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael
다른 필터 조건을 추가하려면
쿼리를 구체화하기 위해
where
절에서 여러 부울 조건을 결합할 수 있습니다. 다음 코드는 쿼리를 실행하여 첫 번째 점수가 90을 초과하고 마지막 점수가 80 미만인 학생들을 반환하도록 하는 조건을 추가합니다.where
절은 다음 코드와 유사합니다.where student.Scores[0] > 90 && student.Scores[3] < 80
자세한 내용은 where 절을 참조하세요.
쿼리 수정
결과를 정렬하려면
특정 순서로 되어 있는 경우 결과를 더 쉽게 검색할 수 있습니다. 반환된 시퀀스를 소스 요소에서 액세스 가능한 필드 기준으로 정렬할 수 있습니다. 예를 들어, 다음
orderby
절은 각 학생의 성에 따라 결과를 사전순으로 정렬합니다.where
문 바로 다음과select
문 앞에서 다음orderby
절을 쿼리에 추가합니다.orderby student.Last ascending
이제 가장 높은 점수에서 가장 낮은 점수까지 첫 번째 테스트의 점수에 따라 역순으로 결과를 정렬하도록
orderby
절을 변경합니다.orderby student.Scores[0] descending
점수를 볼 수 있도록
WriteLine
형식 문자열을 변경합니다.Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);
자세한 내용은 orderby 절을 참조하세요.
결과를 그룹화하려면
그룹화는 쿼리 식의 강력한 기능입니다. 그룹 절이 있는 쿼리는 그룹 시퀀스를 생성하며, 각 그룹 자체는
Key
및 해당 그룹의 모든 멤버로 구성된 시퀀스를 포함합니다. 다음과 같은 새 쿼리는 학생 성의 첫 글자를 키로 사용하여 학생들을 그룹화합니다.IEnumerable<IGrouping<char, Student>> studentQuery2 = from student in students group student by student.Last[0];
이제 쿼리 형식이 변경되었습니다. 이제 쿼리를 실행하면
char
형식을 키로 가지고 있고Student
개체의 시퀀스를 가지고 있는 그룹의 시퀀스가 생성됩니다. 쿼리 형식이 변경되었으므로 다음 코드는foreach
실행 루프도 변경합니다.foreach (IGrouping<char, Student> studentGroup in studentQuery2) { Console.WriteLine(studentGroup.Key); foreach (Student student in studentGroup) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: // O // Omelchenko, Svetlana // O'Donnell, Claire // M // Mortensen, Sven // G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo // F // Fakhouri, Fadi // Feng, Hanying // T // Tucker, Lance // Tucker, Michael // A // Adams, Terry // Z // Zabokritski, Eugene
애플리케이션을 실행하고 콘솔 창에서 결과를 봅니다.
자세한 내용은 group 절을 참조하세요.
변수를 암시적으로 형식화하려면
IGroupings
의IEnumerables
를 명시적으로 코딩하는 작업은 지루할 수 있습니다.var
을 사용하여 동일한 쿼리 및foreach
루프를 훨씬 더 편리하게 작성할 수 있습니다.var
키워드는 개체 형식을 변경하지 않고, 형식을 추론하도록 컴파일러에 지시합니다.studentQuery
의 형식 및group
반복 변수를var
로 변경하고 쿼리를 다시 실행합니다. 내부foreach
루프에서 반복 변수의 형식은 여전히Student
로 지정되며 쿼리는 이전과 마찬가지로 작동합니다.student
반복 변수를var
로 변경하고 쿼리를 다시 실행합니다. 정확히 동일한 결과가 표시됩니다.var studentQuery3 = from student in students group student by student.Last[0]; foreach (var groupOfStudents in studentQuery3) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: // O // Omelchenko, Svetlana // O'Donnell, Claire // M // Mortensen, Sven // G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo // F // Fakhouri, Fadi // Feng, Hanying // T // Tucker, Lance // Tucker, Michael // A // Adams, Terry // Z // Zabokritski, Eugene
var에 대한 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.
키 값을 기준으로 그룹을 정렬하려면
이전 쿼리를 실행하면 그룹이 사전순으로 표시되지 않습니다. 이를 변경하려면
group
절 뒤에orderby
절을 제공해야 합니다. 그러나orderby
절을 사용하려면 우선group
절로 만든 그룹에 대한 참조 역할을 하는 식별자가 필요합니다. 다음과 같이into
키워드를 사용하여 식별자를 제공합니다.var studentQuery4 = from student in students group student by student.Last[0] into studentGroup orderby studentGroup.Key select studentGroup; foreach (var groupOfStudents in studentQuery4) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } // Output: //A // Adams, Terry //F // Fakhouri, Fadi // Feng, Hanying //G // Garcia, Cesar // Garcia, Debra // Garcia, Hugo //M // Mortensen, Sven //O // Omelchenko, Svetlana // O'Donnell, Claire //T // Tucker, Lance // Tucker, Michael //Z // Zabokritski, Eugene
이 쿼리를 실행하면 이제 그룹이 사전순으로 정렬되는 것을 알 수 있습니다.
let을 사용하여 식별자를 소개하려면
let
키워드를 사용하여 쿼리 식의 식 결과에 대한 식별자를 소개할 수 있습니다. 이 식별자는 다음 예제에서처럼 편리하게 사용할 수도 있고, 여러 번 계산할 필요가 없도록 표현식의 결과를 저장하여 성능을 향상시킬 수도 있습니다.// studentQuery5 is an IEnumerable<string> // This query returns those students whose // first test score was higher than their // average score. var studentQuery5 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] where totalScore / 4 < student.Scores[0] select student.Last + " " + student.First; foreach (string s in studentQuery5) { Console.WriteLine(s); } // Output: // Omelchenko Svetlana // O'Donnell Claire // Mortensen Sven // Garcia Cesar // Fakhouri Fadi // Feng Hanying // Garcia Hugo // Adams Terry // Zabokritski Eugene // Tucker Michael
자세한 내용은 let 절을 참조하세요.
쿼리 식에서 메서드 구문을 사용하려면
LINQ의 쿼리 구문 및 메서드 구문에 설명된 대로 일부 쿼리 작업은 메서드 구문을 사용해야만 표현할 수 있습니다. 다음 코드는 소스 시퀀스의 각
Student
에 대한 총 점수를 계산한 다음, 해당 쿼리의 결과에 대해Average()
메서드를 호출하여 클래스의 평균 점수를 계산합니다.var studentQuery6 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] select totalScore; double averageScore = studentQuery6.Average(); Console.WriteLine("Class average score = {0}", averageScore); // Output: // Class average score = 334.166666666667
select 절에서 변환 또는 프로젝션하려면
쿼리가 소스 시퀀스의 요소와 다른 요소를 갖는 시퀀스를 생성하는 것은 매우 일반적입니다. 이전 쿼리 및 실행 루프를 삭제하거나 주석으로 처리하고 다음 코드로 바꿉니다. 쿼리는 문자열 시퀀스(
Students
아님)를 반환하며 이 사실은foreach
루프에 반영됩니다.IEnumerable<string> studentQuery7 = from student in students where student.Last == "Garcia" select student.First; Console.WriteLine("The Garcias in the class are:"); foreach (string s in studentQuery7) { Console.WriteLine(s); } // Output: // The Garcias in the class are: // Cesar // Debra // Hugo
이 연습의 앞부분에 있는 코드는 평균 클래스 점수가 약 334임을 나타냅니다. 총점이 클래스 평균보다 큰
Students
의 시퀀스를Student ID
와 함께 생성하려면select
문에서 무명 형식을 사용할 수 있습니다.var studentQuery8 = from student in students let x = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] where x > averageScore select new { id = student.ID, score = x }; foreach (var item in studentQuery8) { Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score); } // Output: // Student ID: 113, Score: 338 // Student ID: 114, Score: 353 // Student ID: 116, Score: 369 // Student ID: 117, Score: 352 // Student ID: 118, Score: 343 // Student ID: 120, Score: 341 // Student ID: 122, Score: 368
다음 단계
C#에서 쿼리 작업의 기본 사항에 익숙해지면 관심이 있는 특정 LINQ 공급자 형식에 대한 설명서와 샘플을 읽을 준비가 된 것입니다.
참조
.NET feedback
The .NET documentation is open source. Provide feedback here.
피드백
다음에 대한 사용자 의견 제출 및 보기