LINQ λ©”μ„œλ“œμ— λŒ€ν•œ λ³΄κ³ μ„œ

1. LINQ κ°œμš”

LINQ(Language Integrated Query)λŠ” .NET μ–Έμ–΄(C#, VB.NET λ“±)μ—μ„œ μ»¬λ ‰μ…˜ 데이터λ₯Ό μ‰½κ²Œ μ§ˆμ˜ν•˜κ³  μ‘°μž‘ν•  수 μžˆλ„λ‘ μ§€μ›ν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€. LINQλŠ” λ‹€μ–‘ν•œ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•˜λ©° μ»¬λ ‰μ…˜(λ°°μ—΄, 리슀트 λ“±)에 λŒ€ν•œ μ •λ ¬, 필터링, λ³€ν™˜ λ“±μ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

LINQ λ©”μ„œλ“œλŠ” 일반적으둜 μ§€μ—° μ‹€ν–‰(Deferred Execution)κ³Ό μ¦‰μ‹œ μ‹€ν–‰(Immediate Execution)을 기반으둜 λ™μž‘ν•©λ‹ˆλ‹€.


2. LINQ μ£Όμš” λ©”μ„œλ“œ 뢄석

2.1 OrderBy λ©”μ„œλ“œ

  • μ—­ν• : μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ₯Ό νŠΉμ • 기쀀에 따라 μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬ν•©λ‹ˆλ‹€.
  • λ°˜ν™˜κ°’: IEnumerable<T> ν˜•νƒœλ‘œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • μ§€μ—° μ‹€ν–‰: OrderBy λ©”μ„œλ“œλŠ” 호좜 μ‹œμ μ—λŠ” 연산이 μˆ˜ν–‰λ˜μ§€ μ•Šκ³ , μ»¬λ ‰μ…˜μ„ μ—΄κ±°ν•  λ•Œ(예: foreach λ˜λŠ” ToList) 정렬이 μˆ˜ν–‰λ©λ‹ˆλ‹€.

예제 μ½”λ“œ

var sortedList = arr.OrderBy(v => v);
  • v => v: μš”μ†Œ 자체λ₯Ό μ •λ ¬ κΈ°μ€€μœΌλ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.

μ„€λͺ…: 이 μ½”λ“œμ—μ„œλŠ” λ°°μ—΄ arr의 값을 μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬ν•˜μ§€λ§Œ, OrderByλŠ” 아직 μ‹€ν–‰λ˜μ§€ μ•Šμ€ μƒνƒœμž…λ‹ˆλ‹€.


2.2 Where λ©”μ„œλ“œ

  • μ—­ν• : μ»¬λ ‰μ…˜μ˜ μš”μ†Œ 쀑 νŠΉμ • 쑰건에 λ§žλŠ” μš”μ†Œλ§Œ ν•„ν„°λ§ν•©λ‹ˆλ‹€.
  • λ°˜ν™˜κ°’: IEnumerable<T> ν˜•νƒœλ‘œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • μ§€μ—° μ‹€ν–‰: Where λ©”μ„œλ“œλŠ” 쑰건을 μ„€μ •ν•  뿐, μ‹€μ œ 연산은 데이터 μ—΄κ±° μ‹œμ μ— μˆ˜ν–‰λ©λ‹ˆλ‹€.

예제 μ½”λ“œ

var evenNumbers = arr.Where(v => v % 2 == 0);
  • 쑰건: v % 2 == 0 β†’ 짝수인 μš”μ†Œλ§Œ ν•„ν„°λ§ν•©λ‹ˆλ‹€.

μ„€λͺ…: WhereλŠ” 쑰건에 λ§žλŠ” 데이터λ₯Ό λ°˜ν™˜ν•˜μ§€λ§Œ, 이 μ‹œμ μ—μ„œ μ‹€μ œ 데이터 연산이 μˆ˜ν–‰λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.


2.3 ToList λ©”μ„œλ“œ

  • μ—­ν• : IEnumerable<T> ν˜•νƒœμ˜ 데이터λ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜κ³  κ²°κ³Όλ₯Ό List<T>둜 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • μ¦‰μ‹œ μ‹€ν–‰: ToList()λ₯Ό ν˜ΈμΆœν•˜λ©΄ LINQ 연산이 μ¦‰μ‹œ μ‹€ν–‰λ˜μ–΄ κ²°κ³Όκ°€ λ©”λͺ¨λ¦¬μ— μ €μž₯λ©λ‹ˆλ‹€.
  • μš©λ„:
    • κ²°κ³Όλ₯Ό λ©”λͺ¨λ¦¬μ— μ €μž₯ν•΄ λΉ λ₯΄κ²Œ μž¬μ‚¬μš©ν•˜κ³ μž ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
    • LINQ λ©”μ„œλ“œμ—μ„œ λ°˜ν™˜λœ IEnumerable<T>λ₯Ό List ν˜•νƒœλ‘œ λ³€ν™˜ν•΄ νŠΉμ • λ©”μ„œλ“œ(예: ForEach)λ₯Ό μ‚¬μš©ν•˜κ³ μž ν•  λ•Œ ν•„μš”ν•©λ‹ˆλ‹€.

예제 μ½”λ“œ

var evenList = arr.Where(v => v % 2 == 0).ToList();
  • Whereλ₯Ό 톡해 ν•„ν„°λ§λœ 데이터λ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜κ³ , κ²°κ³Όλ₯Ό List<int> ν˜•νƒœλ‘œ μ €μž₯ν•©λ‹ˆλ‹€.

2.4 yield ν‚€μ›Œλ“œμ™€ μ§€μ—° μ‹€ν–‰

  • μ—­ν• : yield return ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ§€μ—° μ‹€ν–‰: yield return은 데이터λ₯Ό ν•˜λ‚˜μ”© λ°˜ν™˜ν•˜λ©°, λ‹€μŒ μš”μ†Œλ₯Ό μš”μ²­λ°›μ„ λ•ŒκΉŒμ§€ 싀행을 μ€‘μ§€ν•©λ‹ˆλ‹€. 이둜 인해 λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ„ μ΅œμ†Œν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ‚¬μš© μ‹œμ : 큰 데이터λ₯Ό μ²˜λ¦¬ν•˜κ±°λ‚˜ 쑰건에 따라 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•΄μ•Ό ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.

yield와 GetEnumerator

  • yield return을 μ‚¬μš©ν•˜λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ IEnumerableκ³Ό IEnumeratorλ₯Ό κ΅¬ν˜„ν•΄ μ€λ‹ˆλ‹€.

  • yieldλ₯Ό μ‚¬μš©ν•˜λ©΄ 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•˜λŠ” μƒνƒœ 기계(state machine)κ°€ μƒμ„±λ˜μ–΄ GetEnumerator의 λ™μž‘μ„ κ°„λ‹¨ν•˜κ²Œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

예제 μ½”λ“œ

IEnumerable<int> GetEvenNumbers(int[] arr)
{
    foreach (var v in arr)
    // `foreach`λŠ” `IEnumerable` λ˜λŠ” `IEnumerable<T>`λ₯Ό κ΅¬ν˜„ν•œ λͺ¨λ“  νƒ€μž…μ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. `List<T>`에 ν•œμ •λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    {
        if (v % 2 == 0)
        {
            yield return v; // 짝수인 κ²½μš°μ—λ§Œ λ°˜ν™˜
        }
    }
}

var evenNumbers = GetEvenNumbers(new int[] { 1, 2, 3, 4, 5 });
foreach (var num in evenNumbers)
{`
    Console.WriteLine(num);
}

μ‹€ν–‰ κ²°κ³Ό:

2
4

μ„€λͺ…:

  1. yield return은 쑰건에 λ§žλŠ” 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•©λ‹ˆλ‹€.
  2. 데이터λ₯Ό μš”μ²­ν•  λ•Œλ§Œ 쑰건 검사가 μ‹€ν–‰λ˜λ―€λ‘œ λ©”λͺ¨λ¦¬ νš¨μœ¨μ μž…λ‹ˆλ‹€.
  3. μ§€μ—° μ‹€ν–‰μ˜ λŒ€ν‘œμ μΈ μ˜ˆμ‹œμž…λ‹ˆλ‹€.

컴파일 ν›„ λ™μž‘:

  1. GetEvenNumbers λ©”μ„œλ“œλŠ” IEnumerable<int>λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

  2. yield return은 IEnumerator 객체λ₯Ό μƒμ„±ν•˜κ³  μƒνƒœλ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.

  3. foreach 루프가 GetEnumerator()λ₯Ό ν˜ΈμΆœν•˜λ©΄ μƒνƒœκ°€ μœ μ§€λœ μ—΄κ±°μžκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.

  • IEnumerable을 κ΅¬ν˜„ν•˜λŠ” λͺ¨λ“  μ»¬λ ‰μ…˜μ€ GetEnumeratorλ₯Ό 톡해 μ—΄κ±°μž(IEnumerator)λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

  • yieldλŠ” μ»΄νŒŒμΌλŸ¬κ°€ GetEnumerator λ©”μ„œλ“œμ™€ μƒνƒœ 관리λ₯Ό μžλ™μœΌλ‘œ μƒμ„±ν•˜λ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

  • λ³΅μž‘ν•œ IEnumerator κ΅¬ν˜„ 없이도 yieldλ₯Ό 톡해 κ°„κ²°ν•˜κ²Œ 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


3. μ§€μ—° μ‹€ν–‰ vs μ¦‰μ‹œ μ‹€ν–‰

3.1 μ§€μ—° μ‹€ν–‰ (Deferred Execution)

  • OrderBy, Where와 같은 LINQ λ©”μ„œλ“œλŠ” μ§€μ—° 싀행을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 데이터 연산은 μ»¬λ ‰μ…˜μ΄ μ—΄κ±°λ˜λŠ” μ‹œμ μ— μˆ˜ν–‰λ©λ‹ˆλ‹€. (예: foreach, .ToList() 호좜)

μž₯점:

  • λ©”λͺ¨λ¦¬ μ‚¬μš©μ΄ μ΅œμ ν™”λ©λ‹ˆλ‹€.
  • λΆˆν•„μš”ν•œ 연산을 ν”Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

단점:

  • λ™μΌν•œ 연산을 μ—¬λŸ¬ 번 μ—΄κ±°ν•˜λ©΄ λ‹€μ‹œ 계산이 μˆ˜ν–‰λ©λ‹ˆλ‹€.

μ˜ˆμ‹œ

var query = arr.Where(v => v % 2 == 0);
foreach (var item in query)
{
    Console.WriteLine(item);
}
  • WhereλŠ” μ§€μ—° μ‹€ν–‰λ˜λ―€λ‘œ foreachλ₯Ό ν˜ΈμΆœν•  λ•Œ μ‹€μ œ 필터링이 μˆ˜ν–‰λ©λ‹ˆλ‹€.

3.2 μ¦‰μ‹œ μ‹€ν–‰ (Immediate Execution)

  • ToList()λ‚˜ ToArray()λ₯Ό ν˜ΈμΆœν•˜λ©΄ LINQ 연산이 μ¦‰μ‹œ μ‹€ν–‰λ©λ‹ˆλ‹€.
  • κ²°κ³ΌλŠ” λ©”λͺ¨λ¦¬μ— μ €μž₯λ˜λ―€λ‘œ μ΄ν›„μ—λŠ” λΉ λ₯΄κ²Œ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μž₯점:

  • κ²°κ³Όκ°€ ν•œ 번 κ³„μ‚°λ˜κ³  λ©”λͺ¨λ¦¬μ— μ €μž₯λ©λ‹ˆλ‹€.
  • λ™μΌν•œ 데이터λ₯Ό μ—¬λŸ¬ 번 μ‚¬μš©ν•  λ•Œ μ„±λŠ₯이 κ°œμ„ λ©λ‹ˆλ‹€.

단점:

  • λ©”λͺ¨λ¦¬λ₯Ό μΆ”κ°€λ‘œ μ°¨μ§€ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ

var result = arr.Where(v => v % 2 == 0).ToList();
  • ToList() 호좜 μ‹œμ μ— 필터링이 μ¦‰μ‹œ μ‹€ν–‰λ˜κ³  κ²°κ³Όκ°€ List<int>둜 μ €μž₯λ©λ‹ˆλ‹€.

4. IEnumerable와 List의 차이점

ꡬ뢄 IEnumerable List
μ‹€ν–‰ 방식 μ§€μ—° μ‹€ν–‰ (연산은 ν•„μš”ν•  λ•Œ μˆ˜ν–‰) μ¦‰μ‹œ μ‹€ν–‰ (데이터λ₯Ό λ©”λͺ¨λ¦¬μ— μ €μž₯)
데이터 μ €μž₯ 데이터 μ €μž₯ μ—†μŒ (μ‹€μ‹œκ°„ μ—°μ‚°) 데이터λ₯Ό λ©”λͺ¨λ¦¬μ— μ €μž₯
μž¬μ‚¬μš©μ„± μ—°μ‚° μ‹œλ§ˆλ‹€ λ‹€μ‹œ 계산 이미 μ €μž₯된 κ²°κ³Όλ₯Ό μž¬μ‚¬μš©
μ„±λŠ₯ λ©”λͺ¨λ¦¬ 효율적 μ—°μ‚° 이후 μ ‘κ·Ό 속도 빠름

5. μ’…ν•© 예제

μ•„λž˜λŠ” OrderBy, Where, ToList λ©”μ„œλ“œκ°€ μ‘°ν•©λœ μ˜ˆμ œμž…λ‹ˆλ‹€.

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] arr = { 5, 1, 4, 2, 3 };

        var sortedEvenNumbers = arr
            .OrderBy(v => v)              // μ •λ ¬
            .Where(v => v % 2 == 0)       // 짝수 필터링
            .ToList();                    // μ¦‰μ‹œ μ‹€ν–‰ 및 List λ³€ν™˜

        sortedEvenNumbers.ForEach(v => Console.WriteLine(v)); // κ²°κ³Ό 좜λ ₯

        // int[] arr = { 30, 56, 78, 45, 12, 99, 33 };

        // IEnumerable<int> sub1 = arr.OrderBy((v) => v);
        // IEnumerable<int> sub2 = sub1.Where((v) => v % 2 == 0);
        // List<int> lt = sub2.ToList();

        // lt.ForEach((v) => { Console.WriteLine(v); });
    }
}

μ‹€ν–‰ κ²°κ³Ό:

2
4

μ„€λͺ…:

  1. OrderBy둜 배열을 μ˜€λ¦„μ°¨μˆœ μ •λ ¬ν•©λ‹ˆλ‹€.
  2. Where둜 짝수만 ν•„ν„°λ§ν•©λ‹ˆλ‹€.
  3. ToList()둜 κ²°κ³Όλ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜κ³  List<int>둜 λ³€ν™˜ν•©λ‹ˆλ‹€.
  4. ForEachλ₯Ό μ‚¬μš©ν•΄ κ²°κ³Όλ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

6. κ²°λ‘ 

LINQ λ©”μ„œλ“œλŠ” 데이터λ₯Ό μ •λ ¬(OrderBy), 필터링(Where), λ³€ν™˜(ToList)ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•˜λ©°, μ§€μ—° μ‹€ν–‰κ³Ό μ¦‰μ‹œ μ‹€ν–‰μ˜ κ°œλ…μ„ μ΄ν•΄ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. μ§€μ—° 싀행은 λ©”λͺ¨λ¦¬ νš¨μœ¨μ μ΄μ§€λ§Œ 반볡 μ—°μ‚° μ‹œ μ„±λŠ₯ μ €ν•˜κ°€ λ°œμƒν•  수 있고, μ¦‰μ‹œ 싀행은 λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜μ§€λ§Œ κ²°κ³Όλ₯Ό λΉ λ₯΄κ²Œ μž¬μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

yield return은 LINQ의 μ§€μ—° μ‹€ν–‰κ³Ό μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ 데이터λ₯Ό 순차적으둜 λ°˜ν™˜ν•˜μ—¬ λ©”λͺ¨λ¦¬ μ‚¬μš©μ„ μ΅œμ†Œν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. LINQλ₯Ό 효과적으둜 μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” IEnumerable와 List의 차이점, 각 λ©”μ„œλ“œμ˜ λ™μž‘ 방식, μ‹€ν–‰ μ‹œμ μ„ λͺ…ν™•νžˆ 이해해야 ν•©λ‹ˆλ‹€.