멈추지 않고 끈질기게

[C#] Linq 구문 본문

C#

[C#] Linq 구문

sam0308 2023. 2. 18. 12:30

※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.

※ 해당 포스팅은 .Net 5.0 버전을 기준으로 작성되었습니다.

 

 

이번 포스팅에서는 C#의 Linq 구문에 대해서 알아보겠습니다.

 

1. Linq란

 Linq는 Language integrated Query의 약자로, C#에서 SQL 구문과 흡사한 방식으로 원하는 데이터를 수집할 수 있는 구문입니다. 해당 구문을 사용하려면 System.Linq를 참조하여야 합니다. 간단한 Linq 구문의 구조는 다음과 같습니다.

 

var output = from (변수 이름) in (데이터 출처)

                           where (조건식)

                           orderby (정렬 대상) (정렬 기준)

                           select (수집 대상);

 

 from 뒤에 원하는 변수 이름을 설정하고, in 뒤에 데이터를 검색할 컬렉션을 입력합니다. 배열, 리스트같은 C#의 자료구조에서 검색하고자 한다면 해당 배열이나 리스트의 변수명을 넣으면 됩니다.

 where 뒤에 조건식을 입력하여 원하는 데이터만 걸러낼 수 있습니다. 

 orderby 뒤에는 정렬 대상과 정렬 기준을 입력하여 결과물을 정렬된 상태로 얻을 수 있습니다. 정렬대상은 from 절에서 선언한 변수나 해당 변수의 하위 속성(string 이라면 Length 등)이 될 수 있으며, 정렬 기준은 ascending(오름차순)과 descending(내림차순)이 있습니다(생략할 경우 ascending으로 적용됩니다).

 select 뒤에 수집 대상을 입력하여 최종적으로 수집할 데이터를 정할 수 있습니다. from 절에서 입력한 변수이름을 그대로 사용하여 데이터 원본을 수집할 수 있고, 계산식을 넣어 해당 데이터로 계산한 결과를 수집할 수도 있습니다. Linq 구문은 from 절로 시작하여 select 절로 끝나야 하며, 필요에 따라 where나 orderby와 같은 다른 절은 생략 가능합니다. 참고로 해당 결과물은 IEnumerable<T>의 형태로 출력되기 때문에, 배열이나 리스트의 형태로 저장해두고 싶다면 ToArray(), ToList() 등으로 변환하여야 합니다. 

 

 이 밖에도 group, join과 같은 SQL 구문의 대부분의 문법이 사용 가능하나, SQL에 대한 자세한 내용은 DB 관련 포스팅에서 다루도록 하겠습니다.

 

 

2. 사용 예제

 몇가지 C# 코드로 실제 사용법을 알아보겠습니다.

static void Main(string[] args)
{
    int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    //arr에서 짝수만 뽑아 3을 곱함, 내림차순 정렬
    var output = from num in arr
                 where (num & 1) == 0
                 orderby num descending
                 select num * 3;

    foreach(var item in output)
        Console.Write(item + " ");
}

그림 1. Linq 예제1

 1부터 9까지 포함한 int형 배열을 초기화하고, 해당 배열에서 짝수만 뽑아 3을 곱한 뒤 내림차순으로 정렬하는 코드입니다.  변수 이름으로 num을 설정하였고, arr에서 (num % 1) == 0 을 만족하는 원소만 추출(2, 4, 6, 8)합니다. orderby 절에서 num 기준 내림차순으로 설정하였고(8, 6, 4, 2), select 절에서 num에 3을 곱한 값(24, 18, 12, 6)을 수집하도록 했습니다. 출력해보면 예상 결과대로 나온 것을 확인할 수 있습니다.

 

 물론 구조체나 클래스 타입의 자료구조에도 사용할 수 있습니다.

class Person
{
    public string Name { get; private set; }
    public int Age { get; private set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Person> list = new List<Person>{
            new Person("아무개", 25),
            new Person("홍길동", 17),
            new Person("김철수", 32),
            new Person("이유리", 9)
        };
        //10살 초과인 Person만 수집, 이름 기준 오름차순 정렬
        IEnumerable<Person> output = from person in list
                                     where person.Age > 10
                                     orderby person.Name
                                     select person;

        foreach (Person person in output)
            Console.WriteLine($"이름: {person.Name}, 나이: {person.Age}");
    }
}

그림 2. Linq 예제2

 상기 코드에서는 Person 클래스를 정의한 뒤, Person 타입의 리스트를 초기화하고 해당 리스트에 Linq 구문을 사용하였습니다. where 절에서 Age가 10보다 큰 Person만 걸러내도록 했으며, orderby 절에서는 Name 기준으로 오름차순으로 정렬하도록 했습니다. select 절에서는 데이터 원본을 수집하도록 하여 foreach  구문에서 이름과 나이를 출력하도록 했으며, 여기서 person.Age 혹은 person.Name과 같은 형태로 나이나 이름만을 수집하도록 할 수도 있습니다. 

 

 또한 xml 파일에도 다음과 같이 사용할 수 있습니다.

그림 2. xml 파일

static void Main(string[] args)
{
    //xml 데이터 추출
    XElement xe = XElement.Load("D:\\kyungho\\TestXml.xml");
    //점수가 60점 이상인 사람의 이름 수집
    var output = from item in xe.Descendants("text")
                 where int.Parse(item.Element("score").Value) >= 60
                 select item.Element("name").Value;

    foreach(var name in output)
        Console.WriteLine(name);
}

그림 2. xml 파일에서 데이터 수집

 맨 위의 이미지는 엑셀을 통해서 간단하게 작성한 xml 파일이며, 코드는 해당 xml 파일을 읽어들인 뒤 Linq 구문을 통해 데이터를 수집하는 내용입니다. 모든 데이터의 상위 태그인 text 태그의 데이터들을 가져온 뒤, score 태그의 값이 60 이상인 데이터만 걸러내고 해당 데이터의 name 값을 수집하였습니다. foreach를 통해 출력하면 60점 이상인 사람 이름만 나오는 모습을 확인할 수 있습니다.

 

3. Linq의 장단점

 Linq 구문을 사용하면 위와 같이 각종 자료구조나 외부 파일 등에서 원하는 데이터를 수집할 수 있으며, 반복문을 돌며 조건에 맞는 데이터를 수집하는 것에 비해 간결하고 읽기 쉬운 코드로 작성할 수 있습니다. 또한 문법 자체가 SQL의 문법과 거의 비슷하므로 SQL에 익숙하다면 금방 사용법을 익힐 수 있습니다.

 

 다만 코드가 짧을 뿐, 실행 과정도 짧은 것이 아니기에 주의해야 합니다. 결국 Linq 구문을 사용해도 해당 자료구조 혹은 파일의 모든 데이터를 돌며 수행하는 것이기 때문입니다. 특히 orderby로 정렬까지 수행할 경우 몇 줄 안되는 Linq 구문이 보기보다 많은 비용을 요구할 수 있으며, 쿼리를 어떻게 짜느냐에 따라서 반복문을 통한 연산보다 되려 많은 비용을 소모할 수도 있으므로 주의해야 합니다.

'C#' 카테고리의 다른 글

[C#] StringBuilder  (0) 2023.02.20
[C#] 가비지 컬렉터(Garbage Collector)  (0) 2023.02.20
[C#] 대리자(Delegate)  (0) 2023.02.09
[C#] IComparable 인터페이스, Comparison<T> 대리자  (0) 2023.01.31
[C#] 딕셔너리(Dictionary)  (0) 2023.01.27