[로봇활용_12주차] C# LINQ(Language-Integrated Query)

최윤호·2025년 10월 30일
post-thumbnail

복잡한 데이터를 우아하게 다루기

C#에서는 조건에 맞는 데이터만 골라내거나, 원하는 순서대로 정렬하고,
또 그중에서 필요한 정보만 쏙쏙 뽑아내야 할 때가 있습니다.
보통 이런 작업을 하려면 forforeach반복문을 쓰고, 그 안에
if조건문을 넣어서 새로운 리스트에 추가하는 등 꽤 번거로운 과정을 거치게 되는데요.
코드가 길어지고 복잡해지면 "내가 지금 뭘 하고 있었지?"하고 길을 잃기 십상입니다.
이런 데이터 처리의 번거로움을 마법처럼 해결해 주는 C#의 강력한 기능,
LINQ(Language-Integrated Query)에 대해 알아보려고 합니다.

1)LINQ는 왜 필요할까요?

LINQ가 왜 필요한지 알려면, LINQ가 없던 시절을 먼저 떠올려보는 게 좋습니다.
예를 들어, 게임 캐릭터 목록이 있고, 여기서 "레벨이 30 이상인
전사(Warrior)만 찾아서 레벨 순으로 정렬"
해야 한다고 상상해 봅시다.

[코드]

using System;
using System.Collections.Generic;

// 먼저 캐릭터 정보를 담을 Player 클래스를 만듭니다.
public class Player
{
    public string Name { get; set; }
    public int Level { get; set; }
    public string Class { get; set; }
}

class Program
{
    static void Main()
    {
        // 데이터 준비
        var players = new List<Player>
        {
            new Player { Name = "용기사", Level = 45, Class = "Warrior" },
            new Player { Name = "마법사", Level = 50, Class = "Mage" },
            new Player { Name = "성기사", Level = 32, Class = "Warrior" },
            new Player { Name = "추적자", Level = 28, Class = "Thief" },
            new Player { Name = "주술사", Level = 38, Class = "Mage" },
            new Player { Name = "전사", Level = 15, Class = "Warrior" }
        };

        // 이제 LINQ 없이 이 문제를 해결해 보겠습니다.
        // 1. 레벨 30 이상인 전사를 담을 새로운 리스트 생성
        var highLevelWarriors = new List<Player>();

        // 2. 모든 플레이어를 순회하며 조건 확인
        foreach (var player in players)
        {
            if (player.Level >= 30 && player.Class == "Warrior")
            {
                highLevelWarriors.Add(player);
            }
        }

        // 3. 레벨 순으로 정렬 (내림차순)
        highLevelWarriors.Sort((p1, p2) => p2.Level.CompareTo(p1.Level));

        // 4. 결과 출력
        foreach (var player in highLevelWarriors)
        {
            Console.WriteLine($"이름: {player.Name}, 레벨: {player.Level}");
        }
    }
}

[실행 결과]

이름: 용기사, 레벨: 45
이름: 성기사, 레벨: 32

결과는 잘 나오지만, 코드가 꽤 길죠?
이런 코드가 쌓이면 가독성이 떨어지고 유지보수도 어려워집니다.

2)LINQ란?

LINQ'Language-Integrated Query', 즉 '언어 통합 쿼리'의 약자입니다.
이름 그대로 C#에서 데이터 질의(Query) 기능을 통합한 기술이에요.
마치 데이터베이스에 SQL 쿼리를 날려 원하는 데이터를 가져오듯,
C#의 리스트, 배열 등 모든 데이터 컬렉션에 선언적으로 물어볼 수 있습니다.

여기서 선언적(Declarative)이라는 말이 중요해요!
"어떻게(How)" 데이터를 찾을지 일일이 명령하는 대신,
"무엇을(What)" 원하는지만 선언하는 방식이죠.
"레벨 30 이상의 전사를 레벨 순으로 원해!"라고 말하는 것과 같아요.

3)LINQ 기본 문법 파헤치기

이제 위에서 풀었던 문제를 LINQ를 사용해서 다시 해결해 보겠습니다.
코드가 얼마나 간결해지는지 직접 확인해 보세요!

[코드]

using System;
using System.Collections.Generic;
using System.Linq; // LINQ를 사용하기 위해 필요

public class Player
{
    public string Name { get; set; }
    public int Level { get; set; }
    public string Class { get; set; }
}

class Program
{
    static void Main()
    {
        // 데이터 준비
        var players = new List<Player>
        {
            new Player { Name = "용기사", Level = 45, Class = "Warrior" },
            new Player { Name = "마법사", Level = 50, Class = "Mage" },
            new Player { Name = "성기사", Level = 32, Class = "Warrior" },
            new Player { Name = "추적자", Level = 28, Class = "Thief" },
            new Player { Name = "주술사", Level = 38, Class = "Mage" },
            new Player { Name = "전사", Level = 15, Class = "Warrior" }
        };

        // LINQ를 사용한 코드
        var highLevelWarriors = from player in players
                                where player.Level >= 30 && player.Class == "Warrior"
                                orderby player.Level descending
                                select player;

        // 결과 출력
        foreach (var player in highLevelWarriors)
        {
            Console.WriteLine($"이름: {player.Name}, 레벨: {player.Level}");
        }
    }
}

[실행 결과]

이름: 용기사, 레벨: 45
이름: 성기사, 레벨: 32

마치 영어 문장을 읽는 것처럼 코드가 훨씬 자연스러워졌죠?
이제 각 키워드가 어떤 역할을 하는지 하나씩 살펴볼게요.

1. from

  • from [변수명] in [데이터 소스]형태로 작성합니다.
  • "players리스트에 있는 각 항목을 player라고 부를게" 라는 의미입니다.
  • 모든 LINQ 쿼리의 시작점이라고 할 수 있어요.
from player in players

2. where

  • where [조건식]형태로 작성합니다.
  • 데이터를 필터링하는 역할을 합니다. if문과 똑같다고 생각하시면 돼요.
  • &&(AND), ||(OR) 연산자를 사용해 여러 조건을 조합할 수 있습니다.
where player.Level >= 30 && player.Class == "Warrior"

3. orderby

  • orderby [정렬 기준]형태로 작성합니다.
  • 데이터를 정렬하는 역할을 합니다.
  • 기본값은 오름차순(ascending)이며,
    내림차순으로 정렬하고 싶다면 descending을 붙여줍니다.
// 레벨을 기준으로 내림차순 정렬
orderby player.Level descending

4. select

  • select [결과]형태로 작성합니다.
  • 필터링과 정렬을 거친 데이터에서 최종적으로 어떤 형태로 결과를 뽑아낼지 결정합니다.
  • select player처럼 데이터 전체를 선택할 수도 있고,
    select player.Name처럼 특정 속성만 선택할 수도 있습니다.
  • 심지어 새로운 형태의 객체(익명 타입)를 만들어 반환할 수도 있어요.
  • select는 질의 결과를 IEnumerable<T>로 반환합니다.
// Player 객체 전체를 선택
select player

// 이름만 선택해서 문자열 리스트로 반환
// var warriorNames = from ... select player.Name;

// 이름과 레벨만 가진 새로운 객체로 만들어 반환
/*
select new { 
    CharacterName = player.Name, 
    CharacterLevel = player.Level 
};
*/

4)정리

데이터 처리를 우아하게 만들어주는 LINQ에 대해 알아봤습니다.
LINQ를 사용하면 '어떻게(How)'가 아닌 '무엇을(What)'
집중할 수 있게 되어 코드의 가독성과 생산성이 크게 향상됩니다.

키워드역할비유
from데이터 소스를 지정"이 상자 안에서 찾아봐"
where데이터를 필터링"빨간색 공만 골라줘"
orderby데이터를 정렬"크기가 큰 순서대로 줄 세워줘"
select최종 결과를 선택"골라낸 공들의 이름표만 나에게 줘"
profile
🚀 미래의 엔지니어를 꿈꾸는 훈련생의 기록 📝

0개의 댓글