[유니티 LINQ] LINQ(Language Integrated Query)


LINQ란?

– LINQ(Language Integrated Query)는 .NET 언어(C#, VB.NET 등)에서 데이터를 쿼리하고
조작하기 위한 강력한 기능을 제공하고 있다.

– LINQ를 사용하면 SQL 데이터베이스, XML 문서, 배열 및 컬렉션과 같은 다양한 데이터 소스에
대해 일관된 구문을 사용하여 데이터 접근이 훨씬 간결하고 직관적으로 보인다.

  • LINQ를 Unity에서 접목 시키면 좋은 점.
  1. 데이터 관리가 간편해진다. 더 쉽게 검색하고, 필터링 할 수 있으며, 정렬 할 수 있다.
  2. 코드의 가독성과 유지 보수에 좋다.

√ LINQ의 주요 기능 사용 예제(Where, Select, OrderBy, FirstOrDefault)

01. Where

where을 사용하면 원본 배열에서 특정 조건을 만족하는 요소들을 필터링 할 때 사용된다.

using System.Linq;
using UnityEngine;

public class EnemyManager : MonoBehaviour {
    public GameObject[] enemies;

    void Start() {
        //게임오브젝트의 position.x > 100f 보다 큰 게임오브젝트를 찾아서 리스트 생성.
        var result = enemies.Where(enemy => enemy.transform.position.x > 100f);
    }
}


요약
Where는 필터링 작업에 유용하다. 특정 조건에 해당하는 데이터들로 새로운 배열을 생성할 수 있으며, 데이터 처리와 검색 작업을 간단하고 효율적으로 처리 할 수 있다.

02. Select

select는 해당 리스트의 데이터를 변형하여 다른 형태의 데이터로 반환할 때 사용된다.
예를 들어 데이터의 특정 속성만 추출하거나, 데이터를 다른 형태로 매핑할 때 유용하다.
게임 오브젝트의 이름 목록을 얻거나, 게임 오브젝트의 위치 값들로 생성할 수 있다.

using System.Linq;
using UnityEngine;

public class EnemyManager : MonoBehaviour {
    public GameObject[] enemies;

    void Start() {
        //게임오브젝트 배열의 name들로 리스트 생성.
        var result = enemies.Select(enemy => enemy.name);
    }
}


요약
Select는 배열 요소를 다양한 형태로 변환 할 수 있으며, 데이터 처리와 가공에 매우 유용하다.

03. OrderBy 및 OrderByDescending

OrderByOrderByDescending는 해당 리스트를 정렬하는데 사용된다.
특정 속성을 기준으로 오름차순, 내림차순 정렬을 할 수 있다.

using System.Linq;
using UnityEngine;

public class EnemyManager : MonoBehaviour {
    public GameObject[] enemies;

    void Start() {
        //enemy의 hp를 기준으로 오름차순 정렬.
        var hpList = enemies.OrderBy(enemy => enemy.hp);

        //enemy의 mp를 기준으로 내림차순 정렬.        
        var mpList = enemies.OrderByDescending(enemy => enemy.mp);
    }
}


요약
Unity에서 게임 데이터를 다룰 때, 정렬 기능을 사용하면 데이터를 효율적으로 정렬하고 관리할 수 있다.
특히 점수판, 리더보드, 인벤토리 아이템 정렬 등 다양한 상황에서 활용할 수 있다.

04. FirstOrDefault

FirstOrDefault는 조건을 만족하는 첫 번째 요소를 검색하는 데 사용된다.
만약 조건을 만족하는 요소가 없다면, 참조 타입의 경우 null, 값 타입의 경우 기본 값 0이 반환 된다.

using System.Linq;
using UnityEngine;

public class EnemyManager : MonoBehaviour {
    public GameObject[] enemies;

    void Start() {
        //게임오브젝트 배열에서 이름이 "EnemyBoss"인 첫 번째 오브젝트를 찾아서 반환.
        var boss = enemies.FirstOrDefault(enemy => enemy.name == "EnemyBoss");

        if (enemy != null) {
            //이름이 "EnemyBoss" 오브젝트를 찾음.
        }
        else {
            //이름이 "EnemyBoss" 오브젝트를 못 찾음.
        }
    }
}


요약
Unity에서 게임 데이터를 다룰 때, FirstOrDefault를 사용하면 조건에 만족하는 첫번째 데이터를 빠르게 찾을 수 있다. 만약 조건에 만족하는 데이터가 없을 때도 예외 처리를 간단히 할 수 있는 장점도 있다.


LINQ 메서드를 복합적으로 사용하면 더욱 강력하고 간결한 코드를 작성할 수 있다.
예를 들어, Where와 Select를 조합하여 특정 조건을 만족하는 요소를 필터링하고,
그 요소의 특정 속성을 추출하는 작업을 한 줄의 코드로 처리할 수 있다.
여기에 FirstOrDefault까지 포함하여 복합적으로 사용 가능 하다.

using System.Linq;
using UnityEngine;

public class GameManager : MonoBehaviour {
    public GameObject[] gameObjects;

    void Start() {
        //활성화된 게임오브젝트 중 첫 번째 오브젝트의 이름 추출
        var name = gameObjects.Where(obj => obj.activeSelf)
                              .Select(obj => obj.name)
                              .FirstOrDefault();

        if (name != null) {
            //활성화 중인 첫번째 게임오브젝트 이름 확인 o
        }
        else {
            //활성화 중인 첫번째 게임오브젝트 이름 확인 x
        }
    }
}

LINQ를 사용하면 코드를 간결하고 가독성 있게 작성할 수 있지만, 내부적으로는 다양한 데이터 구조를 순회하고 변환하기 때문에 성능 면에서 비용이 발생할 수 있다.
특히, LINQ로 쿼리를 작성하면 호출이 많이 발생하여 박싱 및 가비지 생성이 증가할 수 있기 때문에 사용에 있어서 주의 해야 한다.

성능이 중요한 경우 LINQ를 사용하지 않고, 대신 for 루프와 리스트를 사용하는 것이 좋다.
메모리 할당과 가비지 생성을 최소화하여 성능을 향상시킬 수 있기 때문이다.

using System.Linq;
using UnityEngine;

public class GameManager : MonoBehaviour {
    public GameObject[] gameObjects;

    void Start() {
        string[] strings = { "apple", "banana", "cherry", "date", "elderberry" };

        //1. LINQ와 정규식을 사용하여 'e'가 포함된 단어를 찾고 대문자로 변환하는 예시.
        var result = strings
            .Where(s => Regex.IsMatch(s, "e"))
            .Select(s => s.ToUpper())
            .ToArray();
            
        
        //2. for 루프와 리스트를 사용하여 'e'가 포함된 단어를 찾고 대문자로 변환하는 예시.
        List<string> resultList = new List<string>();

        foreach (var s in strings) {
            if (s.Contains("e")) {
                resultList.Add(s.ToUpper());
            }
        }
    }
}

따라서, 상황에 맞게 두 접근 방식을 균형 있게 사용하는 것이 좋다.
– 성능이 중요한 부분에서는 for문
– 가독성과 유지보수성이 중요한 부분에서는 LINQ

  1. 성능 요구 사항: 성능이 중요한 경우(특히 실시간 시스템이나 게임 개발에서), for문 사용.
  2. 코드 가독성 및 유지보수성: 코드의 가독성과 유지보수성이 중요한 경우 LINQ를 사용.
  3. 작업 복잡도: 복잡한 데이터 쿼리와 변환 작업이 필요한 경우 LINQ가 더 적합할 수 있다.
    하지만, 단순한 반복 작업은 for문으로도 충분 하다.

Leave a Comment