유니티 C# 프로그래밍에서 List를 다룰 때
List의 요소들을 다루는 일은 꽤나 코딩이 길어 질 수 있다.
하지만 LINQ를 사용한다면 꽤나 코드를 간결화 가능하다.
#. 첫번째 : List<Vector3> 에서 현재 위치와 2f 보다 멀리 떨어져 있는 요소 필터링하기
public List<Vector3> positionList; //원본 Vector 리스트
public List<Vector3> filter_positionList; // 필터 후 담을 Vector 리스트
// for문을 사용한 경우
public void NormalFuntion()
{
for (int i = 0; i < positionList.Count; i++)
{
if (Vector3.Distance(transform.position, positionList[i]) > 2f)
filter_positionList.Add(positionList[i]);
}
}
// LINQ를 사용한 경우
public void LINQFuntion()
{
filter_positionList = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.ToList();
}
이 필터링에서는 LINQ와 for문 구문의 차이가 거의 없게 비슷하다.
하지만 규칙이 더 추가된다면 어떻게 될까?
#. 두번째 : List<Vector3> 에서 현재 위치와 2f 보다 멀리 떨어져 있는 요소를 오름차순으로 필터링하기
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MyTest : MonoBehaviour
{
public List<Vector3> positionList; //원본 Vector 리스트
public List<Vector3> filter_positionList; // 필터 후 담을 Vector 리스트
// for문을 사용한 경우
public void NormalFuntion()
{
filter_positionList = new List<Vector3>();
List<Vector3> pre_filter_positionList = new List<Vector3>();
for (int i = 0; i < positionList.Count; i++)
{
if (Vector3.Distance(transform.position, positionList[i]) > 2f)
pre_filter_positionList.Add(positionList[i]);
}
for (int i = 0; i < pre_filter_positionList.Count; i++)
{
int l_higherNum = 0;
for (int j = 0; j < filter_positionList.Count; j++)
{
if (Vector3.Distance(transform.position, pre_filter_positionList[i])
> Vector3.Distance(transform.position, filter_positionList[j]))
l_higherNum++;
}
filter_positionList.Insert(l_higherNum, pre_filter_positionList[i]);
}
}
// LINQ를 사용한 경우
public void LINQFuntion()
{
filter_positionList = new List<Vector3>();
filter_positionList = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.OrderBy(n => Vector3.Distance(transform.position, n))
.ToList();
}
}
이제 상당한 차이를 보이기 시작한다. 명시성에도 차이가 나서
for문은 주석이 없다면 어떤 필터링을 거쳤는지 알기도 힘들어진다.
이렇듯 LINQ를 복잡한 필터링을 거칠 때 사용하기에 적합하다.
# LINQ 사용하기
LINQ는 데이터 소스를 가져오고, 쿼리 규칙을 만들고, 실행하는 3단계로 이루어져 있다.
앞서 설명했던 LINQ 구문에서는 간소화되어있었지만, 기본형식은 다음과 같이 IEnumerable을 사용한다.
IEnumerable<Vector3> l_filter_positionList = positionList // 데이터 소스 가져오기
.Where(n => Vector3.Distance(transform.position, n) > 2f); // 쿼리 규칙 만들기
foreach (Vector3 position in l_filter_positionList) // 실행하기
{
Debug.Log(position);
}
foreach등으로 열거자를 사용할 일이 없이 바로 리스트로 출력하고 싶은경우 아래와 같이 .ToList(); 를 사용해 고정시킨다.
var l_filter_positionList = positionList // 데이터 소스 가져오기
.Where(n => Vector3.Distance(transform.position, n) > 2f) // 쿼리 규칙 만들기
.ToList(); // 실행하기
# Method syntax / Query syntax
LINQ는 Method syntax 형식과 Query syntax 두가지 표현방법이 있는데 다음과 같다.
public Vector3 add_positionList;
public void LINQFuntion1() // method syntax
{
var l_filteredList = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.ToList();
}
public void LINQFuntion2() // query syntax
{
var l_filteredList2 =
(from n in positionList
where Vector3.Distance(transform.position, n) > 2f
select n).ToList();
}
유창한 구문의 경우 한줄로 풀어서 써보면 체인 형식으로 이루어 진 것을 확인 할 수 있다.
positionList.Where(n => Vector3.Distance(transform.position, n) > 2f).ToList();
# LINQ 사용하기
#. Where()
조건식이 true인 요소만 필터링한다.
// 예시 1
.Where(n => Vector3.Distance(transform.position, n) > 2f)
// 예시 2
.Where(n => n == new Vector3(-2f,0f,0f));
위와 같이 bool 로 표현되는 식으로 필터링합니다.
#. First()
첫 번째 요소를 반환
public void LINQFuntion()
{
Vector3 firstPosition = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.First(); // 첫 번쨰 요소를 반환한다.
}
#. OrderBy() / OrderByDescending() / Reverse()
오름차순 정렬 / 내림차순 정렬 / 요소의 순서를 반대로 정렬
public void LINQFuntion()
{
Vector3 firstPosition = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.OrderBy(n => Vector3.Distance(transform.position, n))
.First(); // 첫 번쨰 요소를 반환한다.
}
# 지연된 처리 (Lazy)LINQ는 '지연된 처리'라는 중요한 특성을 가지고 있다.
데이터 소스를 가져오고 - 쿼리 식을 만들고 - 실행 하는 3단계로 진행되는데,
쿼리 식은 만들기만하고 실제 데이터의 처리는 실행 단계에서 모두 이루어진다.
즉 쿼리 식을 만들고 - 원본 데이터를 수정하고 - 실행 하는 식으로 중간 처리도 가능하다는 이야기.
public void LINQFuntion2()
{
var l_filteredList2 =
from n in positionList
where Vector3.Distance(transform.position, n) > 2f
select n;
positionList.Add(add_positionList); // 데이터 소스에 요소를 더한다.
filter_positionList = l_filteredList2.ToList(); // 더해진 요소가 포함되어 연산된다.
}
이 때문에 생길 수 있는 오류가 제법 예상되니, 아예 식을 만들면서 형변환을 통해 고정시켜버리는 방법도있다.
public void LINQFuntion1()
{
var l_filteredList = positionList
.Where(n => Vector3.Distance(transform.position, n) > 2f)
.ToList(); // 리스트로 고정시킨다.
positionList.Add(add_positionList); // 원본데이터를 더한다.
filter_positionList = l_filteredList; // 더해진 데이터가 반영되지않는다.
}
'🌍 Unity > 유니티 프로그래밍' 카테고리의 다른 글
사운드/오디오 매니저 Unity Sound Manager (0) | 2019.07.29 |
---|---|
Unity Fade in Fade out 유니티 페이드 인 페이드 아웃 스크립트 (0) | 2019.06.30 |
유니티에서 물리 오류가 나는 경우의 대부분은 FixedUpdate. (0) | 2019.05.29 |
Unity Script checkbox 유니티 스크립트 체크박스가 없을 때 (0) | 2019.05.23 |
유니티 Touch로 카메라 회전 ( Unity Touch camera rotate ) (0) | 2019.02.03 |