关于 UE4 的 TArray
TArray,是UE4的可动态扩容数组容器,是UE4里最常见,也是用的最多的一种容器,类似于STL中的vector
1. 遍历Array的三种方法
1.1 下标遍历Array(lambda写法)
1 // 下标法遍历 Array 2 auto Foreach_1 = [](TArray<int32> _arr)->void 3 { 4 for (int32 i = 0; i < _arr.Num(); i++) 5 { 6 UE_LOG(LogTemp, Display, TEXT("Foreach_1: arr[%d] == %d"), i, _arr[i]); 7 } 8 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 9 };
1.2 foreach 遍历Array(lambda写法)
1 // foreach 遍历 Array 2 auto Foreach_2 = [](TArray<int32> _arr)->void 3 { 4 if (_arr.Num() > 0) 5 { 6 for (int32 val : _arr) 7 { 8 UE_LOG(LogTemp, Display, TEXT("Foreach_2: arr == %d"), val); 9 } 10 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 11 } 12 };
1.3 迭代器遍历Array(lambda写法)
1 // 迭代器遍历 Array 2 auto Foreach_3 = [](TArray<int32> _arr)->void 3 { 4 if (_arr.Num() > 0) 5 { 6 for (TArray<int32>::TConstIterator it = _arr.CreateConstIterator(); it; ++it) 7 { 8 UE_LOG(LogTemp, Display, TEXT("Foreach_3: arr == %d"), *it); 9 } 10 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 11 } 12 };
2. Array 的操作
这里所有代码时放置到Actor对象的BeginPlay方法中执行的,并且这里会使用上方的迭代器遍历Array
1 void AArrayActor::BeginPlay() 2 { 3 Super::BeginPlay(); 4 5 // 下标法遍历 Array 6 auto Foreach_1 = [](TArray<int32> _arr)->void 7 { 8 for (int32 i = 0; i < _arr.Num(); i++) 9 { 10 UE_LOG(LogTemp, Display, TEXT("Foreach_1: arr[%d] == %d"), i, _arr[i]); 11 } 12 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 13 }; 14 15 // foreach 遍历 Array 16 auto Foreach_2 = [](TArray<int32> _arr)->void 17 { 18 if (_arr.Num() > 0) 19 { 20 for (int32 val : _arr) 21 { 22 UE_LOG(LogTemp, Display, TEXT("Foreach_2: arr == %d"), val); 23 } 24 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 25 } 26 }; 27 28 // 迭代器遍历 Array 29 auto Foreach_3 = [](TArray<int32> _arr)->void 30 { 31 if (_arr.Num() > 0) 32 { 33 for (TArray<int32>::TConstIterator it = _arr.CreateConstIterator(); it; ++it) 34 { 35 UE_LOG(LogTemp, Display, TEXT("Foreach_3: arr == %d"), *it); 36 } 37 UE_LOG(LogTemp, Display, TEXT(" ========================= ")); 38 } 39 }; 40 41 TArray<int32> Arr; 42 TArray<int32> Arr_2; 43 Arr_2.Init(88, 1); 44 // 初始化 45 Arr.Init(1, 2); // 初始化内存,初始化类型为int32,每个内存的数据为2,一共初始化3个int32 46 Foreach_3(Arr); 47 48 49 // 增加元素,返回 Index 50 Arr.Add(2); // Add 提供了引用和右值引用两个版本,会将元素插入到数组的最后位置,并返回元素的Index,内部实现都是通过 CheckAddress() 检查参数有效性并调用Emplace函数。 51 Arr.Emplace(3); // Emplace 只有右值引用版本,在数组的末尾构造一个新项,可能会重新分配整个数组以适应。也是 Add 调用的方法,Add 只是比他多了数据有效性检查。 52 Arr.Push(4); // 为了方便C语言语法所存在的方法。其源码分引用与右值引用两个版本。其实现是直接调用 Add 方法 53 Foreach_3(Arr); 54 55 // 将另一个数组添加到数组(大批量添加) 56 Arr.Append(Arr_2); // 大批量Add时可以使用,参数为另一个数组。注意右值参数的版本,内部实现可以看到不能避免新分配内存 57 Arr += Arr_2; // 与AppEnd一样,大批量添加元素时可以使用 58 Foreach_3(Arr); 59 60 // 指定位置添加 61 Arr.Insert(0, 3); // 将元素0添加到指定下标3的位置,同样这个函数提供了包括右值,GetRef多个版本方便使用。 62 Foreach_3(Arr); 63 64 // 增加元素,返回增加元素的引用,与上方的Add Emplace 内部实现是一致的,唯一区别是返回值是元素的引用而不是元素的Index 65 Arr.Add_GetRef(5); // 提供了引用与右值应用两个版本,返回新插入元素的引用;在参数传入后先检查了安全性,然后调用了 Emplace_GetRef 66 Arr.Emplace_GetRef(6); // 在数组的末尾构造一个新项,可能会重新分配整个数组以适应。也是 Add_GetRef 调用的方法,Add_GetRef 只是比他多了数据有效性检查。 67 Foreach_3(Arr); 68 69 // 增加元素,保证插入的元素不是重复的,如果重复就返回已经存在的那个Index 70 Arr.AddUnique(6); 71 Arr.AddUnique(7); 72 Arr.AddUnique(8); 73 Foreach_3(Arr); 74 75 // 删除元素 76 Arr.Remove(1); // 删除与参数相等的所有参数,其是用 RemoveAll 实现的 77 Foreach_3(Arr); 78 Arr.RemoveAll([](const int32 &vel) {return vel < 4; }); // 删除所有符合条件的元素 79 Foreach_3(Arr); 80 Arr.RemoveAt(0, 2, true); // 删除指定位置区间的参数,三个参数:1. 从下标几开始。2. 删除几个元素。3. 删除后的内存是否需要释放。 81 Foreach_3(Arr); 82 Arr.RemoveAtSwap(0, 2, true); //在对数组元素的顺序要求不是那么高的情况下,可以使用这个 RemoveAtSwap 函数。这个函数和RemoveAt不同的是在移除之后将数组最后一个元素挪到删除的位置而其他元素位置都保持不变这样就不存在遍历移动的耗时操作了,对于性能要求很高但顺序要求不高的场合下,用这个函数性能会更好一些。 83 Foreach_3(Arr); 84 85 // 查找元素 86 UE_LOG(LogTemp, Display, TEXT("(7)Index = %d"), Arr.Find(7)); // 查找元素在Array中的下标位置,查找到返回下标,否则返回-1 87 UE_LOG(LogTemp, Display, TEXT("(8)Index = %d"), Arr.Find(8)); 88 UE_LOG(LogTemp, Display, TEXT("(9)Index = %d"), Arr.Find(9)); 89 }
打印结果:
2.2 关于 TArry 的排序
1 TArray<int32> KeyList; 2 KeyList.Add(1); 3 KeyList.Add(0); 4 KeyList.Add(3); 5 KeyList.Add(5); 6 KeyList.Add(2); 7 KeyList.Add(4); 8 if (KeyList.Num() > 0) 9 { 10 for (int32 KeyNode : KeyList) 11 { 12 UE_LOG(LogTemp, Display, TEXT("Key: %d"), KeyNode); 13 } 14 UE_LOG(LogTemp, Display, TEXT("======================")); 15 16 // 使用 Array 的 Sort (快速排序) 排序后重新输出,排序参数是lambda,< 为升序排序,>为降序排序 17 KeyList.Sort([](int32 A, int32 B)->bool {return A < B; }); 18 for (int32 KeyNode : KeyList) 19 { 20 UE_LOG(LogTemp, Display, TEXT("Sort | Key: %d"), KeyNode); 21 } 22 UE_LOG(LogTemp, Display, TEXT("======================")); 23 24 // 使用 Array 的 HeapSort (堆排序) 排序后重新输出,排序参数是lambda,< 为升序排序,>为降序排序 25 KeyList.HeapSort([](int32 A, int32 B)->bool {return A > B; }); 26 for (int32 KeyNode : KeyList) 27 { 28 UE_LOG(LogTemp, Display, TEXT("HeapSort | Key: %d"), KeyNode); 29 } 30 UE_LOG(LogTemp, Display, TEXT("======================")); 31 32 // 使用 Array 的 StableSort () 排序后重新输出,排序参数是lambda,< 为升序排序,>为降序排序 33 KeyList.StableSort([](int32 A, int32 B)->bool {return A < B; }); 34 for (int32 KeyNode : KeyList) 35 { 36 UE_LOG(LogTemp, Display, TEXT("StableSort | Key: %d"), KeyNode); 37 } 38 UE_LOG(LogTemp, Display, TEXT("======================")); 39 }
打印结果