[언리얼 엔진] 배열 TArray
- ⭐ Game Programming/Unreal Document
- 2021. 8. 10.
언리얼 엔진의 배열 TArray
- TArray는 문자그대로 배열 컨테이너이며, 언리얼 엔진(Unreal Engine)에서 가장 자주 쓰이는 컨테이너 클래스이다.
만들고 채우기
- Init 함수로 배열을 같은 엘리먼트 사본으로 입력받은 갯수만큼 채운다
//배열의 선언
TArray<int32> IntArray;
//Init 함수로 채우기
IntArray.Init(10, 5); //InitArray = [10,10,10,10,10]
- Add와 Emplace 함수로 배열 끝에 항목을 추가할 수 있다.
- Add는 객체를 복사하여 배열에 넣고 Emplace는 객체를 배열안에서 생성한다.
- 간단한 유형(int, float 등)은 Add를 사용해도 무방하지만
- 복잡한 구조체를 엘리먼트로 사용할때는 Emplace가 효율이 더 좋다.
//배열 끝에 추가하기
TArray<FString> StrArray;
StrArray.Add(TEXT("Hello"));
StrArray.Emplace(TEXT("World"));
//StrArray = ["Hello", "World"]
- Append 함수는 같은 유형의 다른 TArray 또는 일반 배열을 한꺼번에 추가가 가능하다.
FString Arr[] = { TEXT("of"), TEXT("Tomorrow") };
StrArray.Append(Arr, ARRAY_COUNT(Arr));
// StrArray = ["Hello","World","of","Tomorrow"]
- AddUnique 함수는 기존 컨테이너에 동일한 엘리먼트가 존재할 경우 추가하지 않아 중복된 데이터가 컨테이너에 포함되지 않도록 한다.
- 엘리먼트에 operator== 연산자가 있어야한다.
StrArray.AddUnique(TEXT("!"));
// StrArray = ["Hello","World","of","Tomorrow"]
StrArray.AddUnique(TEXT("!"));
// 추가되지 않는다.
// StrArray = ["Hello","World","of","Tomorrow"]
- Insert 함수는 단일 값이나 배열 값을 입력한 인덱스 위치에 추가한다.
StrArray.Insert(TEXT("Brave"), 1);
// StrArray = ["Hello","Brave","World","of","Tomorrow"]
- SetNum 함수는 배열의 크기를 설정할 수 있다.
- 설정한 값이 현재 배열보다 큰 경우 기본 생성자의 값으로 추가
- 배열보다 작은경우 뒤에서부터 항목을 제거
StrArray.SetNum(8);
// StrArray == ["Hello","Brave","World","of","Tomorrow","!","",""]
StrArray.SetNum(6);
// StrArray == ["Hello","Brave","World","of","Tomorrow","!"]
반복처리
- C++의 auto를 이용한 for 기능으로 반복처리 할 수 있다. (추천)
- 인덱스 기반의 반복 처리또한 가능하다.
- 반복자(iterator)를 통한 반복 처리도 가능하다.
FString JoinedStr;
for (auto& Str : StrArray)
{
JoinedStr += Str;
JoinedStr += TEXT(" ");
}
for (int32 Index = 0; Index != StrArray.Num(); ++Index)
{
JoinedStr += StrArray[Index];
JoinedStr += TEXT(" ");
}
for (auto It = StrArray.CreateConstIterator(); It; ++It)
{
JoinedStr += *It;
JoinedStr += TEXT(" ");
}
// JoinedStr == "Hello Brave World of Tomorrow ! "
정렬
- TArray는 Sort함수로 간단한 정렬이 가능하다.
- 엘리먼트의 < 연산자를 사용하여 배열을 정렬한다.
- 2번째 인자에 조건을 직접 작성하여 정렬도 가능하다.
- HeapSort함수로 힙정렬이 가능하다.
- Sort와 HeapSort는 조건이 같은 값들의 순서를 기존과 동일하게 보장하지 않는 안정적이지 않은 정렬 함수
- StableSort는 정렬이후 기존의 순서를 보장하지만 좀 더 느리다.
StrArray.Sort();
// StrArray == ["!","Brave","Hello","of","Tomorrow","World"]
StrArray.Sort([](const FString& A, const FString& B) {
return A.Len() < B.Len();
});
// StrArray == ["!","of","Hello","Brave","World","Tomorrow"]
StrArray.HeapSort([](const FString& A, const FString& B) {
return A.Len() < B.Len();
});
// StrArray == ["!","of","Hello","Brave","World","Tomorrow"]
StrArray.StableSort([](const FString& A, const FString& B) {
return A.Len() < B.Len();
});
// StrArray == ["!","of","Brave","Hello","World","Tomorrow"]
쿼리
- Num 함수는 배열의 갯수를 확인 할 수 있다.
int32 Count = StrArray.Num();
// Count == 6
- GetData 함수는 배열의 포인터를 반환한다.
FString* StrPtr = StrArray.GetData();
// StrPtr[0] == "!"
// StrPtr[1] == "of"
// ...
// StrPtr[5] == "Tomorrow"
// StrPtr[6] - out of Index
- [] 연산자로 인덱스 접근이 가능하다
- [] 연산자는 레퍼런스를 반환하기 때문에 배열이 const가 아니라면 엘리먼트의 값을 변경할 수 있다.
FString Elem1 = StrArray[1];
// Elem1 == "of"
StrArray[3] = StrArray[3].ToUpper();
// StrArray == ["!","of","Brave","HELLO","World","Tomorrow"]
- IsValidIndex 함수는 이름 그대로 인자값이 유효한 인덱스인지 검사한다
bool bValidM1 = StrArray.IsValidIndex(-1);
bool bValid0 = StrArray.IsValidIndex(0);
bool bValid5 = StrArray.IsValidIndex(5);
bool bValid6 = StrArray.IsValidIndex(6);
// bValidM1 == false
// bValid0 == true
// bValid5 == true
// bValid6 == false
- Last 함수는 배열의 끝에서부터 역순으로 인덱스 접근을 한다
- Top 함수는 Last와 같지만 인덱스접근이 불가능하다 (항상 끝 항목 접근)
FString ElemEnd = StrArray.Last();
FString ElemEnd0 = StrArray.Last(0);
FString ElemEnd1 = StrArray.Last(1);
FString ElemTop = StrArray.Top();
// ElemEnd == "Tomorrow"
// ElemEnd0 == "Tomorrow"
// ElemEnd1 == "World"
// ElemTop == "Tomorrow"
- Contains는 배열에 특정 값을 검사할 수 있다.
- ContainsByPredicate 함수는 술부(Predicate)를 작성하여 검사조건을 직접 정의할 수 있다.
bool bHello = StrArray.Contains(TEXT("Hello"));
bool bGoodbye = StrArray.Contains(TEXT("Goodbye"));
// bHello == true
// bGoodbye == false
bool bLen5 = StrArray.ContainsByPredicate([](const FString& Str){
return Str.Len() == 5;
});
bool bLen6 = StrArray.ContainsByPredicate([](const FString& Str){
return Str.Len() == 6;
});
// bLen5 == true
// bLen6 == false
- Find함수로 특정 값에 대한 배열 인덱스값을 얻을 수 있다.
- 값을 찾을 수 없다면 INDEX_NONE 값이 반환된다
- 중복된 값이 있다면 첫번째로 발견한 인덱스값이 반환 된다
- FindLast는 마지막으로 발견한 인덱스값이 반환된다.
int32 Index;
if (StrArray.Find(TEXT("Hello"), Index))
{
// Index == 3
}
int32 IndexLast;
if (StrArray.FindLast(TEXT("Hello"), IndexLast))
{
// IndexLast == 3, because there aren't any duplicates
}
int32 Index2 = StrArray.Find(TEXT("Hello"));
int32 IndexLast2 = StrArray.FindLast(TEXT("Hello"));
int32 IndexNone = StrArray.Find(TEXT("None"));
// Index2 == 3
// IndexLast2 == 3
// IndexNone == INDEX_NONE
- IndexOfByKey 함수는 엘리먼트와 다른 타입의 비교가 가능하다.
- 단 operator==(ElementType, OtherType)이 존재할 경우에 동작한다.
- IndexOfByPredicate 함수는 설정한 술부로 조건을 정하여 해당 조건에 부합하는 엘리먼트의 인덱스값을 반환한다.
int32 Index = StrArray.IndexOfByKey(TEXT("Hello"));
// Index == 3
int32 Index = StrArray.IndexOfByPredicate([](const FString& Str){
return Str.Contains(TEXT("r"));
});
// Index == 2
- FindByKey 함수는 IndexOfByKey 함수와 동일하게 검색하지만 포인터를 반환한다.
- FindByPredicate 또한 IndexOfByPredicate처럼 검색하고 포인터를 반환한다.
auto* OfPtr = StrArray.FindByKey(TEXT("of")));
auto* ThePtr = StrArray.FindByKey(TEXT("the")));
// OfPtr == &StStrArrayrArr[1]
// ThePtr == nullptr
auto* Len5Ptr = StrArray.FindByPredicate([](const FString& Str){
return Str.Len() == 5;
});
auto* Len6Ptr = StrArray.FindByPredicate([](const FString& Str){
return Str.Len() == 6;
});
// Len5Ptr == &StrArray[2]
// Len6Ptr == nullptr
- FilterByPredicate 함수는 배열에서 술부의 조건에 만족하는 항목들을 모아 새로 만든 배열을 반환한다.
TArray<FString> Filter = StrArray.FilterByPredicate([](const FString& Str){
return Str.Num() == 5;
});
// Filter == ["Brave","Hello","World"]
제거
- Remove 함수로 배열에서 엘리먼트를 지울수 있다.
- == 연산자로 동일한 엘리먼트들을 삭제
- RemoveSingle 함수는 처음으로 일치한 엘리먼트를 삭제한다.
- RemoveAt은 인덱스로 위치를 지정하여 해당 엘리먼트를 삭제한다.
- RemoveAt 사용시 인덱스가 유효한지 검사해야한다
- RemoveAll 함수는 술부를 이용하여 조건에 만족하는 모든 항목을 삭제 한다.
TArray<int32> ValArr;
int32 Temp[] = { 10, 20, 30, 5, 10, 15, 20, 25, 30 };
ValArr.Append(Temp, ARRAY_COUNT(Temp));
// ValArr == [10,20,30,5,10,15,20,25,30]
ValArr.Remove(20);
// ValArr == [10,30,5,10,15,25,30]
ValArr.RemoveSingle(30);
// ValArr == [10,5,10,15,25,30]
ValArr.RemoveAt(2); // 인덱스 2 엘리먼트를 제거
// ValArr == [10,5,15,25,30]
ValArr.RemoveAt(99); // 런타임 오류가 발생
ValArr.RemoveAll([](int32 Val) {
return Val % 3 == 0;
});
// ValArr == [10,5,25]
- RemoveSwap, RemoveAtSwap, RemoveAllSwap 함수는 기존 함수에 비해 부하가 적다
- 그러나 제거후 나머지 엘리먼트의 순서를 보장할 수 없다.
- Empty함수는 모든 항목을 제거한다.
TArray<int32> ValArr2;
for (int32 i = 0; i != 10; ++i)
ValArr2.Add(i % 5);
// ValArr2 == [0,1,2,3,4,0,1,2,3,4]
ValArr2.RemoveSwap(2);
// ValArr2 == [0,1,4,3,4,0,1,3]
ValArr2.RemoveAtSwap(1);
// ValArr2 == [0,3,4,3,4,0,1]
ValArr2.RemoveAllSwap([](int32 Val) {
return Val % 3 == 0;
});
// ValArr2 == [1,4,4]
ValArr2.Empty();
// ValArr2 == []
참고
반응형