반응형
배경
- C# 버전 3.0에 추가된 기능
- C# 버전 3.0은 Visual Studio 2008과 함께 2007년 말에 출시되었지만 언어 기능을 완전히 갖춘 버전은 .NET Framework 버전 3.5와 함께 제공됨
사용이유
private 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}}
};
- 위와 같은 List를 처리해야 하는 경우 (예 : JSON 파싱) LINQ가 필요
예제 - ID가 111 이상 114 미만인 학생 출력 (LINQ 사용 X)
List<Student> studentList = new List<Student>();
foreach (var list in students)
{
if (list.ID >= 111 && list.ID < 114)
{
studentList.Add(list);
}
}
foreach (var list in studentList)
{
Console.WriteLine($"{list.First}'s ID : {list.ID}");
}
예제 - ID가 111 이상 114 미만인 학생 출력 (LINQ 사용 O)
var studentList = from student in students
where student.ID >= 111
where student.ID < 114
select student;
foreach (var list in studentList)
{
Console.WriteLine($"{list.First}'s ID : {list.ID}");
}
결과
LINQ의 기본 : from, where, orderby, select
# from
- 모든 LINQ 쿼리식은 반드시 from 절로 시작한다.
- from의 데이터 원본은 아무 형식이나 사용할 수 없고, IEnumerable<T> 인터페이스를 상속하는 형식이어야 한다.
- 배열, 컬렉션 객체들은 IEnumerable<T>를 상속하기 때문에 from 절의 데이터 원본으로 사용할 수 있다.
- from <범위 변수> in <데이터 원본>의 형식으로 사용
LINQ의 범위 변수와 foreach 문의 반복 변수의 차이점
- foreach 문의 반복 변수는 데이터 원본으로부터 데이터를 담아내지만, 범위 변수는 실제로 데이터를 담지는 않는다.
- 쿼리식 외부에서 선언된 변수에 범위 변수의 데이터를 넣는 일은 할 수 없다.
예제 - 짝수만 출력
int[] numbers = { 9, 2, 6, 4, 5, 3, 7, 8, 1, 10 };
var result = from n in numbers
where n % 2 == 0
orderby n
select n;
foreach (int n in result)
{
Console.WriteLine($"짝수 : {n}");
}
결과
# where
- from 절이 데이터 원본으로부터 뽑아낸 범위 변수가 가져야 하는 조건을 where에 작성한다.
# orderby
- 데이터 정렬을 수행하는 연산자이다.
- defalut 값은 MSSQL과 마찬가지로 오름차순(ascending)이다.
- 내림차순은 descending을 입력해주면 된다.
# select
- 최종 결과를 추출하는 쿼리식의 마침표 같은 존재이다.
- LINQ 질의 결과는 IEnumerable<T>로 반환되는데, 이 때 T는 select문에 의해 결정된다.
예제 - 짝수 ID를 가진 사람의 First NAme 출력
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}}
};
var result = from student in students
where student.ID % 2 == 0
select student.First;
foreach (var n in result)
{
Console.WriteLine($"결과 : {n}");
}
결과
비교
- First 변수의 타입이 string이기 때문에 IEnumerable<string> 형식으로 컴파일된다.
예제 - 새로운 형식 생성
var result = from student in students
where student.ID % 2 == 0
select new { student.First, NewID = student.First + student.ID.ToString() };
foreach (var n in result)
{
Console.WriteLine($"{n.First} : {n.NewID}");
}
결과
여러 개의 데이터 원본에 질의
- from 문을 중첩해서 사용하셔 여러 개의 데이터 원본에 접근할 수 있다.
예제 - Scores에 60 미만의 값이 있는 사람 출력
- 리스트 -
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}}
};
- 코드 -
var results = from student in students
from score in student.Scores
where score < 60
select new { student.First, Score = score };
foreach (var result in results)
{
Console.WriteLine($"{result.First} : {result.Score}");
}
결과
group by로 데이터 분류
- group by 절은 다음의 형식으로 사용된다.
group A by B into C |
- A에는 from 절에서 뽑아낸 범위 변수
- B에는 분류 기준
- C는 그룹 변수
예제 - Scores 평균이 85이상, 미만 분류
var results = from student in students
group student by student.Scores.Average() >= 85 into g
select new { GroupKey = g.Key, Profiles = g };
foreach (var group in results)
{
Console.WriteLine($"평균 85점 이상 : {group.GroupKey}");
foreach (var profile in group.Profiles)
{
Console.WriteLine($"\t{profile.First}의 평균점수 : {profile.Scores.Average()}");
}
}
결과
두 데이터 원본을 연결하는 join
내부 조인
- 내부 조인은 교집합과 비슷하다.
- 두 테이블의 필드를 비교할 때 '==' 연산자가 아닌 'equals' 라는 키워드를 사용한다.
- 내부 조인은 다음의 형식으로 사용된다.
from a in A join b in B on a.XX equals b.YY |
예제
- 리스트 -
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}}
};
List<StudentGrade> studentGrades = new List<StudentGrade>
{
new StudentGrade {ID=111, Grade=1},
new StudentGrade {ID=112, Grade=2},
new StudentGrade {ID=114, Grade=3},
new StudentGrade {ID=119, Grade=2},
new StudentGrade {ID=122, Grade=3},
new StudentGrade {ID=140, Grade=5}
};
- 코드 -
var results = from student in students
join grade in studentGrades on student.ID equals grade.ID
select new
{
student.ID,
student.First,
grade.Grade
};
foreach (var result in results)
{
Console.WriteLine($"ID : {result.ID} | Name : {result.First} | Grade : {result.Grade}");
}
결과
외부 조인
- 연결할 데이터 원본에 기준 데이터 원본의 데이터와 일치하는 데이터가 없다면 그 부분은 빈 값으로 결과를 채우게 된다.
- LINQ는 LEFT JOIN만 지원한다.
- 사용방법
- join 절을 이용해서 조인을 수행한 후 그 결과를 임시 컬렉션에 저장한다.
- 임시 컬렉션에 대해 DefaultIfEmpty 연산을 수행해서 비어있는 조인 결과에 빈 값을 채워 넣는다.
- DefaultIfEmpty 연산을 거친 임시 컬렉션에서 from 절을 통해 범위 변수를 뽑아낸다.
- 이 범위 변수와 기준 데이터 원본에서 뽑아낸 범위 변수를 이용해서 결과를 추출한다.
예제
var results = from student in students
join grade in studentGrades on student.ID equals grade.ID into a
from grade in a.DefaultIfEmpty(new StudentGrade() { ID = 0 })
select new
{
student.ID,
student.First,
grade.Grade
};
foreach (var result in results)
{
Console.WriteLine($"ID : {result.ID} | Name : {result.First} | Grade : {result.Grade}");
}
결과
반응형
'C# > Study' 카테고리의 다른 글
[복습]애트리뷰트 - Attribute, C# (0) | 2021.01.01 |
---|---|
[복습] Reflection - C#, 리플렉션 (0) | 2020.12.28 |
[복습] 인덱서 - C# (0) | 2020.12.21 |
[복습] Delegate - C#, CSharp, 씨샵, 델리게이트, 대리자 (0) | 2020.12.15 |
[C# 공부] Thread(쓰레드) - 비동기 호출, Delegate - 짱우의 코딩일기 - 티스토리 (0) | 2020.04.07 |