TArray 是UE 用来替换C++ 标准库中的vector。STL 虽然十分优秀,但是用在游戏领域,则存在内存分配上的问题,主要体现在内存利用率不够高、分配速度慢。笔者曾在最短路算法中使用vector 等标准库容器,32G 内存直接溢出,后改用C 语言的数组实现,内存使用量才1G 多。为了解决以上问题,UE 开发出了TArray、TMap、TSet等容器,以全面替代STL 中的vector、map、set等。
本文将总结TArray 的常见用法,总的来说,TArray 的用法与vector 相似,但也有较大区别。
一,TArray 的创建、初始化、赋值TArray 的创建、初始化、赋值的主要形式如下。其中,列表既可以用作构造函数的参数,也可以用来初始化和赋值。Init() 可以在TArray 在放置若干个相同元素。
TArray二,TArray 的元素添加 添加单个元素Arr; //Arr is [] TArray SecArr({ TEXT("Are"), TEXT("you"), TEXT("OK") }); //SecArr is [Are you OK] TArray ThirdArr = { TEXT("Are"), TEXT("you"), TEXT("OK") }; //ThirdArr is [Are you OK] ThirdArr.Init(TEXT("Hello"), 3); //ThirdArr is [Hello Hello Hello] Arr = { TEXT("Hello"), TEXT("World") }; //Arr is [Hello World]
向TArray 中添加单个元素,有很多中方法:Add、Push、Emplace、AddUnique、Insert。在具体使用上,它们也有一些差别,归纳如下:
- 前四种是在数组尾部追加元素,Insert 可在数组的任意位置插入元素;
- Add 和 Push类似,但是将元素复制或移动到数组中,而Emplace 则使用给定参数构建元素类型的新实例;通常来说,Emplace 的效率高于Add;
- 如果不存在相同元素(用运算符=判断),AddUnique 才会向数组中添加元素。
各个函数的使用方式如下:
TArray添加多个元素Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") }; Arr.Add(TEXT(",")); //Arr is [Are you OK ,] Arr.Push(TEXT("Hello")); //Arr is [Are you OK , Hello] Arr.Emplace(TEXT("World")); //Arr is [Are you OK , Hello World] Arr.AddUnique(TEXT(",")); //Arr is [Are you OK , Hello World] Arr.AddUnique(TEXT("I")); //Arr is [Are you OK , Hello World I] Arr.Insert(TEXT("Head"), 0); //Arr is [Head Are you OK , Hello World I]
向数组中添加多个元素,可采用Append() 方法或 += 操作符完成,使用方法如下:
TArray三,TArray 的三种遍历Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") }; TArray SecArr({ TEXT("How"), TEXT("Do"), TEXT("You") }); Arr.Append(SecArr); //Arr is [Are you OK How Do You] TArray ThirdArr({ TEXT("I"), TEXT("Am"), TEXT("Fine") }); Arr += ThirdArr; //Arr is [Are you OK How Do You I Am Fine]
TArray 的遍历一共有三种形式:范围for 循环、索引、迭代器,这一点上和vector 类似。下面展示了这几种遍历的使用方法。
TArray四,TArray 的三种排序Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") }; for (auto& s : Arr) { UE_LOG(LogTemp, Warning, TEXT("%s"), *s); } for (int i = 0; i < Arr.Num(); i++) { UE_LOG(LogTemp, Warning, TEXT("%d: %s"), i, *Arr[i]); } for (auto It = Arr.CreateIterator(); It; ++It) { UE_LOG(LogTemp, Warning, TEXT("%s"), *(*It)); }
TArry的排序方法也有三种:Sort、HeapSort、StableSort。他们的简单使用方法如下:
Arr.Sort(); Arr.HeapSort(); Arr.StableSort();
三者并不相同,存在如下差异:
- Sort 基于快速排序,是不稳定的排序;
- HeapSort 基于堆排序,是不稳定的排序;
- StableSort 基于归并排序,是稳定的排序。
默认情况下,上述三种排序方法都是使用元素类型的 < 运算符进行排序。我们可以使用lambda 自定义排序规则,如下,我们根据字符串长度对FString 排序。
TArray五,TArray 的元素删除Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") ,TEXT("Hello"), TEXT("World") }; Arr.StableSort( [](const FString& A, const FString& B) {return A.Len() < B.Len(); } ); //Arr is [OK Are you Hello World]
删除元素的方法比较多,有Remove()、RemoveSingle()、RemoveAll()、RemoveAt()、Empty()。总结下来,它们的用法如下:
- Remove(Str): 删除数组中所有与 Str 相同的元素,是否相同用 == 运算符判断;
- RemoveSingle(Str):删除数组中第一个与 Str 相同的元素,是否相同用 == 运算符判断;
- RemoveAll(lambda):删除数组中的多个元素,删除规则由lambda 表达式指定;
- RemoveAt(i):删除数组中索引为 i 的元素;
- Empty():并不是判断数组为空,而是清空所有元素;
- Remove(Str) 与 RemoveSingle(Str) 的区别在于是删除单个元素,还是所有元素;
- Remove(Str) 与 RemoveAll(lambda) 的区别在于删除规则的不同。
代码演示如下:
TArray六,TArray 的查询 根据索引获取元素对象的引用:[] 运算符、Last()、Top()Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; Arr.Remove(TEXT("OK")); //Arr is [Are you] Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; Arr.RemoveSingle(TEXT("OK")); //Arr is [Are you OK] Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; Arr.RemoveAll([](const FString& Str) {return Str.Len() == 2; }); //Arr is [Are you] Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; Arr.RemoveAt(0); //Arr is [you OK OK] Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; Arr.Empty(); //Arr is []
使用 [] 运算符、Last()、Top()都可以根据索引获取数组中的元素,并且获取的都是元素的引用,也就是说我们可以直接修改数组中的元素。如下代码所示,执行 Arr[0] = Arr[1] 之后,第 0 个元素的值也变成第 1 个元素的了;执行 Arr.Top() = Arr[1] 之后,最后一个元素的值也变成第 1 个元素的了。这三个方法的联系与区别如下:
- Arr[i] 获取的是顺数第 i 个元素;
- Last(i) 获取的是倒数第 i 个元素 ;
- Top() 不能带参数,实际效果完全和 Last()一样。
三个方法的具体用法如下:
TArray判断元素是否存在:Contains()、ContainsByPredicate()Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") ,TEXT("Hello"), TEXT("World") }; Arr[0] = Arr[1]; // Arr is [you you OK Hello World] UE_LOG(LogTemp, Warning, TEXT("%s"), *Arr.Last()); //Output: World UE_LOG(LogTemp, Warning, TEXT("%s"), *Arr.Last(1)); //Output: Hello UE_LOG(LogTemp, Warning, TEXT("%s"), *Arr.Top()); //Output: World Arr.Top() = Arr[1]; // Arr [you you OK Hello you]
判断数组中是否存在某元素,使用的方法是Contains() 及其变体ContainsByPredicate()。ContainsByPredicate() 允许使用一元谓词指定判断规则。具体用法如下:
TArray查找元素所在的索引:Find()、FindLast()、IndexOfByKey()、IndexOfByPredicate()Arr = { TEXT("Are"), TEXT("you"), TEXT("OK") ,TEXT("Hello"), TEXT("World") }; bool bExist = Arr.Contains(TEXT("Are")); bool bContain = Arr.ContainsByPredicate( [](const FString& Str) {return Str.Len() == 3; } );
查找元素所在的索引,使用的方法是Find()、FindLast()、IndexOfByKey()、IndexOfByPredicate()。如果查找成功,则返回元素所在的索引;查找失败,则返回 INDEX_NONE(值为-1的宏)。他们的用法总结如下:
- Find(Str):返回数组中第一个与 Str 相同的元素的索引,是否相同用 == 运算符判断;
- FindLast(Str):返回数组中最后一个与 Str 相同的元素的索引,是否相同用 == 运算符判断;
- IndexOfByKey(Str):与 Find(Str) 一样;
- IndexOfByPredicate(lambda):IndexOfByKey 的lambda 版,用lambda 表达式来指定查找元素的规则。
代码示例如下:
TArray查找元素对象:FindByKey()、FindByPredicate()、FilterByPredicate()Arr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; int Index = Arr.Find(TEXT("OK")); //Index is 2 Index = Arr.Find(TEXT("I")); //Index is INDEX_NONE Index = Arr.FindLast(TEXT("OK")); //Index is 3 Index = Arr.IndexOfByKey(TEXT("OK")); //Index is 2 Index = Arr.IndexOfByPredicate([](const FString& Str) {return Str.Len() == 3; }); //Index is 0
FindByKey()、FindByPredicate()、FilterByPredicate() 可用来获取数组中的元素对象。FindByKey()、FindByPredicate() 获取的都是指向元素的指针,FilterByPredicate() 获取的是所有符合条件的元素,用法总结如下:
- FindByKey(Str):获取数组中第一个与 Str 相同的元素的指针,获取失败返回nullptr;
- FindByPredicate(lambda):FindByKey 的lambda 版,用lambda 表达式来指定查找元素的规则;
- FilterByPredicate(lambda):获取数组中所有使lambda 表达式为true 的元素,但这些元素都是拷贝,返回一个数组。
TArrayArr = { TEXT("Are"), TEXT("you"), TEXT("OK"), TEXT("OK") }; FString* StrPtr = Arr.FindByKey(TEXT("OK")); //StrPtr 是一个指向字符串"OK"的指针 StrPtr = Arr.FindByPredicate([](const FString& Str) {return Str.Len() == 3; }); //StrPtr 是一个指向字符串"Are"的指针 TArray StrArr = Arr.FilterByPredicate([](const FString& Str) {return Str.Len() == 3; }); //StrArr is [Are you]



