Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[Programming/C#] LINQ의 표준 연산자와 쿼리식 문법 본문

Programming/C#

[Programming/C#] LINQ의 표준 연산자와 쿼리식 문법

scii 2020. 9. 25. 02:23

싱글턴(Singleton)이란?

해당 형식의 객체를 오직 단 하나만 마들고 이 객체를 전역에서 접근할 수 있도록 하는 디자인 기법이다. 기본값이 할당된 컬렉션은 참조용으로만 사용할 것이니 여러 개의 인스턴스가 필요 없다. 싱글턴을 이용하면 메모리 낭비를 줄일 수 있다.

표준 연산자 및 쿼리식 문법의 표

종류 메소드 이름 설명 C# 쿼리식 문법
정렬 OrderBy 오름차순으로 값을 정렬 orderby
OrderByDescending 내림차순으로 값을 정렬 orderby ... descending
ThenBy 오름차순으로 2차 정렬 orderby ..., ...
ThenByDescending 내림차순으로 2차 정렬 orderby ..., ... descending
Reverse 컬렉션 요소의 순서를 거꾸로   
집합 Distinct 중복 값 제거  
Except 두 컬렉션 사이의 차집합을 반환  
Intersect 두 컬렉션 사이의 교집합을 반환  
Union 두 컬렉션 사이의 합집합을 반환  
필터링 OfType 메소드의 형식 매개 변수로 형식 변환이 가능한 값들만 추출  
Where 필터링할 조건을 평가하는 함수를 통과하는 값들만 추출 where
수량 연산 All 모든 요소가 임의의 조건을 모두 만족시키는지를 평가 (true / false)  
Any 모든 요소 중 단 하나의 요소라도 임의의 조건을 만족시키는지를 평가 (true / false)  
Contains 명시한 요소가 포함되어 있는지를 평가 (true / false)  
데이터 추출 Select 값을 추출하여 시퀀스를 만듦 select
SelectMany 여러 개의 데이터 원본으로부터 값을 추출하여 하나의 시퀀스를 만듦 (여러 개의 from 절을 사용)  
데이터 분할 Skip 시퀀스에서 지정한 위치까지 요소들을 건너뜀  
SkipWhile 입력된 조건 함수를 만족시키는 요소들을 건너뜀  
Take 시퀀스에서 지정한 요소까지 요소들을 취함  
TakeWhile 입력된 조건 함수를 만족시키는 요소들을 취함  
데이터 결합 Join 공통 특성을 가진 서로 다른 두 개의 데이터 소스의 객체를 연결 (키가 일치하는 두 객체를 쌍으로 추출) join ... in ... on ... eqauls ...
GroupJoin 기본적으로 Join 연산자와 같은 일을 하되, 조인 결과를 그룹으로 만듦 join ... in ... on ... equals ... into ...
데이터 그룹화 GroupBy 공통된 특성을 공유하는 요소들을 각 그룹으로 묶음. 각 그룹은 IGrouping<(Or <TKey, TElement>)>) 객체로 표현 group ... by 또는 group ... by ... into ...
ToLookup 키(Key) 선택 함수를 이용하여 골라낸 요소들을 Lookup<(OF <(TKey, TElement>)>) 형식의 객체에 삽입 (하나의 키에 여러 개의 객체를 대응시킬 때 사용하는 컬렉션)  
생성 DefaultIfEmpty 빈 컬렉션을 기본값이 할당된 싱글턴 컬렉션으로 바꿈.   
Empty 비어 있는 컬렉션을 반환  
Range 일정 범위의 숫자 시퀀스를 담고 있는 컬렉션을 생성  
Repeat 같은 값이 반복되는 컬렉션을 생성  
동등 여부 평가 SequenceEqual 두 시퀀스가 서로 일치하는지를 평가  
요소 접근  ElementAt 컬렉션으로부터 임의의 인덱스에 존재하는 요소를 반환  
ElementAtOrDefault 컬렉션으로부터 임의의 인덱스에 존재하는 요소를 반환하되, 인덱스가 컬렉션의 범위를 벗어날 때 기본값을 반환  
First 컬렉션의 첫 번째 요소를 반환. 조건식이 매개 변수로 입력되는 경우 이 조건을 만족시키는 첫 번째 요소를 반환  
FirstOrDefault First 연산자와 같은 기능을 하되, 반환할 값이 없는 경우 기본값을 반환  
Last 컬렉션의 마지막 요소를 반환. 조건식이 매배 변수로 입력되는 경우 이 조건을 만족시키는 마지막 요소를 반환  
LastOrDefault Last 연산자와 같은 기능을 하되, 반환할 값이 없는 경우 기본값을 반환  
Single 컬렉션의 유일한 요소를 반환. 조건식이 매개 변수로 입력되는 경우 이 조건을 만족시키는 유일한 요소를 반환  
SingleOrDefault Single 연산자와 같은 기능을 하되, 반환할 값이 없거나 유일한 값이 아닌 경우 주어진 기본값을 반환  
형식 변환 AsEnumerable 매개 변수를 IEnumerable<(Of <T>)>)로 형 변환하여 반환  
AsQueryable (일반환) IEnumerable 객체를 (일반화) IQueryable 형식으로 변환  
Cast 컬렉션의 요소들을 특정 형식으로 변환 범위 변수를 선언할 때 명시적으로 형식을 지정 (ex: from Profile profile in arrProfile)
OfType 특정 형식으로 형 변환할 수 있는 값만을 걸러냄  
ToArray 컬렉션을 배열로 변환. 이 메소드는 강제로 쿼리를 실행  
ToDictionary 키 선택 함수에 근거해서 컬렉션의 요소를 Dictionary<(Of <(TKey, TValue>)>)에 삽입함. 이 메소드는 강제로 쿼리를 실행  
ToList 컬렉션을 List<(Of <(T)>) 형식으로 변환. 이 메소드는 강제로 쿼리를 실행  
ToLookup 키 선택 함수에 근거해서 컬렉션의 요소를 Lookup<(Of <(Tkey, TElement)>)>에 삽입함. 이 메소드는 강제로 쿼리를 실행  
연결 Concat 두 시퀀스를 하나의 시퀀스로 연결  
집계 Aggregate 컬렉션의 각 값에 대해 사용자가 정의한 집계 연산을 수행  
Average 컬렉션의 각 값에 대한 평균을 계산  
Count 컬렉션에서 조건에 부합하는 요소의 개수를 헤아림  
LongCount Count와 동일한 기능을 하지만, 매우 큰 컬렉션을 대상으로 한다는 점이 다름  
Max 컬렉션에서 가장 큰 값을 반환  
Min 컬렉션에서 가장 작은 값을 반환  
Sum 컬렉션 내의 값의 합을 계산  

53개의 표준 LINQ 연산 메소드 중 C#의 쿼리식에서 지원하는 것을 11개뿐이다. 물론 11가지만으로도 대부분의 데이터 처리가 가능하지만, 나머지 42개를 모두 활용할 수 있다면 좋을것이다. 따라서 LINQ 쿼리식과 메소드를 함께 사용하는 방법을 알아둘 필요가 있다.

Book[] arrBook = 
{
    new Book(){Title = "C#", Page = 900},
    new Book(){Title = "C++", Page = 1200},
    new Book(){Title = "Java", Page = 650},
    new Book(){Title = "Python", Page = 450},
    new Book(){Title = "TypeScript", Page = 720}
}

LINQ를 통해 책들의 페이지 수 평균을 구해보자.

var books = from book in arrBook
            where book.Page < 800
            select book;

books는 800페이지 미만의 데이터만 갖고 있는 IEnumerable<Book> 형식의 컬렉션이다. 따라서 LINQ를 사용할 수 있으며, books에 대해 다음과 같이 Average() 메소드를 호출할 수 있다.

double Average = books.Average(book => book.Page);

쿼리식의 결과에 대해 Average() 메소드를 호출하는 코드를 다음과 같이 한 문장으로 묶을 수 있다.

var books = (from book in arrBook
            where book.Page < 800
            select book).Average(book => book.Page);

쿼리식 & 메소드를 함께 사용하는 예제

using System;
using System.Linq;

namespace test
{
    class Book
    {
        public string Title { get; set; }
        public int Page { get; set; }
    }

    internal class Program
    {
        public static void Main(string[] args)
        {
            Book[] arrBook = new Book[]
            {
                new Book() {Title = "C#", Page = 900},
                new Book() {Title = "C++", Page = 1200},
                new Book() {Title = "Dart", Page = 470},
                new Book() {Title = "Java", Page = 800},
                new Book() {Title = "Swift", Page = 600}
            };

            var bookStatus =
                from book in arrBook
                group book by book.Page < 900
                into g
                select new
                {
                    Group = g.Key == true ? "900페이지 미만" : "900페이지 이상",
                    Count = g.Count(),
                    Max = g.Max(book => book.Page),
                    Min = g.Min(book => book.Page),
                    Average = g.Average(book => book.Page)
                };

            foreach (var status in bookStatus)
            {
                Console.WriteLine(
                    "{0} - Count: {1}, Max: {2}, Min: {3}, Average: {4}",
                    status.Group, status.Count, status.Max, status.Min, status.Average);
            }
        }
    }
}


/* 결과

900페이지 이상 - Count: 2, Max: 1200, Min: 900, Average: 1050
900페이지 미만 - Count: 3, Max: 800, Min: 470, Average: 623.333333333333

*/
Comments