}

유니티 LINQ 완전 정복 – Where부터 GroupBy까지

LINQ란? (링크란?)

LINQ는 Language Integrated Query의 줄임말로, C# 언어 안에서 SQL처럼 데이터를 다루는 문법입니다.

리스트나 배열, 딕셔너리, 데이터베이스까지 다양한 컬렉션을 대상으로 사용할 수 있습니다.

 

Where, Select, GroupBy, Any 등에 대해 간단히 설명드리겠습니다.


Where – 조건에 맞는 데이터만 필터링

💬 역할: LINQ에서의 Where는 모든 요소를 돌면서 조건을 만족하는 것만 추출합니다. 즉, “이런 애들만 골라줘!” 명령하는 것이지요.

var activeObjs = FindObjectsOfType<GameObject>()
    .Where(obj => obj.activeSelf);

 

  • Where는 루프와 if를 합친 느낌입니다
  • obj.activeSelf == true인 오브젝트만 필터링합니다
  • 결과는 IEnumerable<GameObject>을 반환합니

 


Select – 데이터를 다른 형태로 가공

💬 역할: LINQ에서의 Selece는 리스트의 요소를 하나씩 꺼내서 원하는 형태로 변형합니다. 즉, "너 이렇게 변해!" 라고 명령하는 것이지요.

var objNames = FindObjectsOfType<GameObject>()
    .Select(obj => obj.name);

 

  • 모든 GameObject에서 name만 추출하고 싶을 때 사용한 경우입니다
  • Where와 차이는, Select는 찾아낸 게임오브젝트의 "이름"만 가져오므로 결과값이 string 리스트 형태입니다. (변형되었쥬)

 


Any – 하나라도 조건을 만족하면 true

💬 역할: LINQ에서의 Any는 조건에 맞는 요소가 하나라도 있으면 true를 반환합니다. 

bool hasCanvas = FindObjectsOfType<GameObject>()
    .Any(obj => obj.GetComponent<Canvas>() != null);

 

  • 오브젝트들 중에서 Canvas 컴포넌트가 하나라도 있으면 true
  • 조건 만족하는 걸 찾자마자 종료하기 때문에 빠릅니

 


All – 모두가 조건을 만족하면 true

bool allActive = FindObjectsOfType<GameObject>()
    .All(obj => obj.activeSelf);

모든 GameObject가 활성화 상태일 경우에만 true입니다.

 


First, FirstOrDefault – 처음 나오는 요소 반환

💬 역할: LINQ에서의 First는 조건에 맞는 첫 번째 요소만 반환합니다. 아래 포스팅에 좀 더 자세히 써놨습니다(자주 사용되더라고요).

 

유니티 FirstOrDefault #LINQ

FirstOrDefault란?주어진 조건을 만족하는 시퀀스에서 첫 번째 요소를 검색하는 LINQ의 메서드입니다. 시퀀스란 저번 Dotween Pro에셋을 소개하면서 짧게 설명해봤습니다. 아래 링크를 참고해주세요! 202

wlsdn629.tistory.com

var firstUI = FindObjectsOfType<GameObject>()
    .FirstOrDefault(obj => obj.name.Contains("UI"));

 

  • 이름에 "UI"가 포함된 오브젝트 중 가장 먼저 찾은 것을 반환합니다
  • 없으면 null을 반환합니다 (First()는 없으면 오류 발생합니다)

 


OrderBy, OrderByDescending – 정렬

💬 역할: LINQ에서의 OrderBy/OrderByDescending은 요소를 오름차순 혹은 내림차순으로 정렬합니다.

var sorted = FindObjectsOfType<GameObject>()
    .OrderBy(obj => obj.name.Length);

 

  • 이름 길이에 따라 정렬하는 경우입니다
  • 내림차순은 OrderByDescending()를 쓰면 됩니다
var sorted = FindObjectsOfType<GameObject>()
    .OrderByDescending(obj => obj.name.Length);

 

 

var players = new List<(string name, int score)>
{
    ("Jinwoo", 80),
    ("Minji", 95),
    ("Haeun", 70),
    ("Sohee", 95),
    ("Taeyang", 60)
};

// 점수 내림차순 정렬 (높은 점수가 먼저 → 순위)
var ranked = players
    .OrderByDescending(p => p.score)
    .ThenBy(p => p.name) // 동점자 알파벳순
    .ToList();

for (int i = 0; i < ranked.Count; i++)
{
    Debug.Log($"{i + 1}위: {ranked[i].name} - {ranked[i].score}점");
}

이런식으로 응용해서 순위를 매기는 알고리즘을 작성할 수 있습니다. 아래는 출력예시입니다.

1위: Minji - 95점
2위: Sohee - 95점
3위: Jinwoo - 80점
4위: Haeun - 70점
5위: Taeyang - 60점

GroupBy – 기준에 따라 묶기

💬 역할: LINQ에서 GroupBy는 요소를 특정 기준에 따라 그룹화(분류)해줍니다.

var grouped = FindObjectsOfType<GameObject>()
    .GroupBy(obj => obj.tag);

 

  • 태그(tag)별로 오브젝트를 묶은 경우입니다
  • 결과는 IGrouping<string, GameObject>의 묶음들을 반환합니다
var grouped = FindObjectsOfType<GameObject>()
    .GroupBy(obj => obj.tag);

foreach (var group in grouped)
{
    Debug.Log($"[Tag: {group.Key}]");

    foreach (var obj in group)
    {
        Debug.Log($"  - {obj.name}");
    }
}

 

이런식으로 응용할 수 있습니다. 출력 결과는 아래와 같습니다.

[Tag: Enemy]
  - Goblin
  - Orc
[Tag: Player]
  - Hero
[Tag: UI]
  - Canvas
  - HealthBar

Count, Sum, Average, Min, Max – 계산 메서드

var texts = new List<TMPro.TextMeshProUGUI>
{
    MakeTMP("Hello"),          // 5글자
    MakeTMP("Welcome to VR!"), // 14글자
    MakeTMP("Score: 100"),     // 10글자
    MakeTMP("UI"),             // 2글자
    MakeTMP("This is a test.") // 15글자
};

// 가상의 MakeTMP 함수는 text 속성만 설정된 TextMeshProUGUI 컴포넌트라고 가정하겠습니다
var texts = FindObjectsOfType<TMPro.TextMeshProUGUI>();

int count = texts.Count();                           // 전체 개수 반환
int totalLength = texts.Sum(txt => txt.text.Length); // 전체 글자 수 반환
double average = texts.Average(txt => txt.text.Length); // 평균 글자 수 반환
int maxLen = texts.Max(txt => txt.text.Length);      // 가장 긴 글자 수 반환

결과는 아래와 같습니다.

전체 개수: 5
전체 글자 수: 46
평균 글자 수: 9.2
가장 긴 텍스트 길이: 15

Distinct – 중복 제거

var names = FindObjectsOfType<GameObject>()
    .Select(obj => obj.name)
    .Distinct();

중복된 이름을 제거합니다. 자세한 내용은 아래 포스팅을 참고해주세요.

 

LINQ의 Distinct() 메서드로 중복 제거하기

데이터를 다룰 때 종종 중복된 값이 문제를 일으키곤 합니다. LINQ에서 제공하는 Distinct() 메서드는 이러한 중복을 쉽게 제거해줍니다. Distinct()의 사용법과 다양한 활용 예제를 살펴보겠습니다.Dis

wlsdn629.tistory.com

 


실제로 실행 

LINQ는 지연 평가이기 때문에 마지막에 ToList()와 같은 트리거를 붙여줘야 실제로 실행됩니다.

즉, ToList()는 단순히 IEnumerable을 List로 바꾸는 역할뿐 아니라, LINQ의 지연 평가를 즉시 실행시키는 트리거 역할도 합니다.
Where, Select 등은 실제로 ToList(), foreach, Count() 등을 만나야 실행이 된다고 기억하시면 되겠습니다.