C#/LINQ

[C#]LINQ 인덱스 가져오는 방법

DevStory 2022. 7. 12.

Select 메서드

System.Linq 네임스페이스에 존재하는 Select() 메서드는 오버로드된 두 가지 버전이 존재합니다.

// 첫 번째 버전
public static IEnumerable<TResult> Select<TSource, TResult>(
  this IEnumerable<TSource> source, 
  Func<TSource, TResult> selector);

// 두 번째 버전
public static IEnumerable<TResult> Select<TSource, TResult>(
  this IEnumerable<TSource> source, 
  Func<TSource, int, TResult> selector);

첫 번째 버전으로는 인덱스를 가져올 수 없으므로 이번 포스팅은 두 번째 버전에 대해 설명합니다.

 

Select() 메서드의 첫 번째  매개 변수는 Select() 메서드가 IEnumerable<T> 인터페이스의 확장 메서드라는 것을 의미합니다. 

this IEnumerable<TSource> source

Select() 메서드의 두 번째 매개 변수는 Func 제네릭 대리자입니다.

- TSource는 source 요소의 타입입니다.

- int는 source  요소의 인덱스입니다.

- TResult는 selector에서 반환하는 값의 타입입니다.

// TSource: 각 요소의 타입
// int: 인덱스
// TResult: 반환 타입
Func<TSource, int, TResult> selector

Func 제네릭 대리자에 대한 내용은 아래 포스팅을 참고해주세요.

 

[C#]람다식, 람다표현식(Lambda expression)

람다식(Lambda expression)이란? 람다식(Lambda)식은 접근자, 함수 이름, return문이 없는 익명 함수(anonymous function)입니다. 람다식을 사용하면 더 짧은 코드를 작성할 수 있으며 코드를 더 가독성 있게 만

developer-talk.tistory.com

다음 예제는 string 타입의 List에 대해 LINQ를 활용하여 List의 요소와 인덱스를 추출합니다.

class Program
{
  static void Main(string[] args)
  {
    List<string> strLi = new List<string>()
    {
      "Java", "C Sharp", "C++", "JavaScript", "React"
    };

    var linqMethodResult = strLi.Select((item, index) => new
    {
      index,
      subject = item
    });

    foreach (var obj in linqMethodResult)
      Console.WriteLine("index: " + obj.index + " / Subject: " + obj.subject);
  }
}

 [실행 결과]

index: 0 / Subject: Java
index: 1 / Subject: C Sharp
index: 2 / Subject: C++
index: 3 / Subject: JavaScript
index: 4 / Subject: React

예제 1. 질의 구문에서 사용

질의 구문의 select절에는 인덱스를 지원하지 않습니다. 하지만, 메서드 구문의 Select() 메서드와 조합해서 사용하면 인덱스를 추출할 수 있습니다.

 

질의 구문과 메서드 구문을 조합하는 방법보다 메서드 구문만 사용하는 코드가 훨씬 깔끔하지만 "이런 방법도 있구나"라는 정도로 이해하면 되겠습니다.

 

다음 예제는 질의 구문에서 인덱스를 추출하는 방법입니다. from절에 추출하고자 하는 데이터에 Select() 메서드를 사용하여 익명 타입의 객체를 생성합니다.

class Program
{
  static void Main(string[] args)
  {
    List<string> strLi = new List<string>()
    {
      "Java", "C Sharp", "C++", "JavaScript", "React"
    };


    var linqQueryResult = from subject in strLi.Select((item, index) => new { index, value = item })
                          select new
                          {
                            index = subject.index,
                            subject = subject.value
                          };

    foreach (var obj in linqQueryResult)
      Console.WriteLine("index: " + obj.index + " / Subject: " + obj.subject);
  }
}

[실행 결과]

index: 0 / Subject: Java
index: 1 / Subject: C Sharp
index: 2 / Subject: C++
index: 3 / Subject: JavaScript
index: 4 / Subject: React

Select() 메서드를 사용하는 방법과 결과는 동일합니다. 하지만 코드가 복잡하므로 LINQ에서 인덱스를 추출하는 경우 질의 구문을 사용하는 방법은 권장하지 않습니다.


예제 2. Where절과 함께 사용

Where절과 함께 사용하는 경우 Select() 메서드를 두 번 호출해야합니다.

- 첫 번째 호출은 데이터의 인덱스와 요소를 가지는 익명 타입의 객체를 생성

- 두 번째 호출은 필터된 항목을 추출

다음 예제는 인덱스를 추출하는 방법과 Where절을 같이 사용하며 문자열이 "C"로 시작하는 요소만 추출합니다.

class Program
{
  static void Main(string[] args)
  {
    List<string> strLi = new List<string>()
    {
      "Java", "C Sharp", "C++", "JavaScript", "React"
    };

    var linqMethodResult = strLi
        .Select((item, index) => new  // 첫 번째 호출. 인덱스와 요소를 가지는 익명 타입의 객체 생성
        {
          index,
          subject = item
        })
        .Where(item => item.subject.StartsWith("C")) // "C"로 시작하는 요소를 필터
        .Select(item => new                          // 필터된 항목을 추출
        { 
          index = item.index,
          subject = item.subject
        });

    foreach (var obj in linqMethodResult)
      Console.WriteLine("index: " + obj.index + " / Subject: " + obj.subject);
  }
}

[실행 결과]

index: 1 / Subject: C Sharp
index: 2 / Subject: C++
반응형

댓글