UE C++基础 | 常用数据容器 | TArray、TMap、TSet
- Unreal最常用的三种数据容器为
TArray、TMap、TSet
。 - 因为这三种容器是支持引擎反射的。(在蓝图中使用)
TArray
- TArray 是虚幻C++中的动态数组。
- TArray 特点: 速度快,内存消耗小,安全性高。
- TArray 所有元素均完全为相同类型,不能进行不同元素类型的混合。
初始化
TArray<int32> IntArray; // 创建一个空数组
增
// 使用 Init 初始化数组
IntArray.Init(8, 5); // [8,8,8,8,8]
// 使用 Add 或 Emplace 添加数组元素
// Emplace 可以避免创建不必要的临时变量,效率比 Add 高。
IntArray.Add(5); // ==> [8,8,8,8,8,5]
IntArray.Emplace(3); // ==> [8,8,8,8,8,5,3]
TArray<int32> IntArrayB;
IntArrayB.Init(3, 2); // ==> [3,3]
int32 IntArrayC[] = {6, 6};
// 使用 Append 可以将其它的 TArray 或 常规数组 一次性添加在后面。
IntArray.Append(IntArrayB); // ==> [8,8,8,8,8,5,3,3,3]
IntArray.Append(IntArrayC, ARRAY_COUNT(IntArrayC)); // ==> [8,8,8,8,8,5,3,3,3,6,6]
// 使用 AddUnique 添加一个TArray中不存在的元素,如果已经存在则不会添加。
IntArray.AddUnique(1); // ==> [8,8,8,8,8,5,3,3,3,6,6,1]
IntArray.AddUnique(1); // ==> 无法添加
// 使用 Insert 在指定索引处插入元素。
IntArray.Insert(4, 1); // ==> [8,4,8,8,8,8,5,3,3,3,6,6,1]
// 使用 SetNum 设置 TArray 元素数量,如果大于当前数量,则使用元素类型的默认构造函数创建新元素,如果数量小于当前数量,则将移除多余的元素。
// 通常在初始化后分配一个数量。
IntArray.SetNum(5); // ==> [8,4,8,8,8]
IntArray.SetNum(8); // ==> [8,4,8,8,8,0,0,0]
删
// IntArray == [3,3,6,2,1,3,8,3,7,5]
// 使用 RemoveSingle 只会移除TArray中与传入元素相等的最靠前的一个元素。
IntArray.RemoveSingle(3) // ==> [3,6,2,1,3,8,3]
// 使用 Remove 会移除与传入元素相等的所有元素,
IntArray.Remove(3) // ==> [6,2,1,8,7,5]
// 使用 RemoveAt 按元素索引移除元素,索引必须存在,否则会出现运行时错误。
IntArray.RemoveAt(2) // ==> [6,2,8,7,5]
// 使用 RemoveAll 以 Lambda 表达式的方式来移除具有某些特征的所有元素。
IntArray.RemoveAll([](const int32& Num){Num % 2 == 0}) // ==> [7,5]
// 使用 Pop 移除最后一个元素。
IntArray.Pop(); // ==> [7]
// 使用 Empty 移除数组中所有元素。
IntArray.Empty(); // ==> []
// 使用 Reset 移除数组中所有元素,但不释放内存。
IntArray.Reset(); // ==> []
// 当元素被移除时,其后的元素会向前移,移动过程存在开销。
// 可使用 RemoveSwap、RemoveAtSwap 和 RemoveAllSwap 来减少开销, 通过牺牲剩余元素的排序将不被保证。
改
- 排序
// StringArray == ["!", "Food", "Good", "Hi", "Animal", "Nice"]
// 使用[]索引直接修改值
IntArray[0] = TEXT("?") // ==> ["?", "Food", "Good", "Hi", "Animal", "Nice"]
// 使用 Sort 进行排序
IntArray.Sort() // ==> ["?", "Animal", "Food", "Good", "Hi", "Nice"]
// 使用 Sort 提供 lambda 谓词进行排序
IntArray.Sort([](const FString& A, const FString& B){
return A.Len() < B.Len();
}) // ==> ["?", "Hi", "Good", "Food", "Nice", "Animal"]
// 使用 HeapSort 提供堆排序
IntArray.HeapSort([](const FString& A, const FString& B){
return A.Len() < B.Len();
}) // ==> ["?", "Hi", "Good", "Food", "Nice", "Animal"]
// 使用 StableSort 提供稳定排序,排序后保证等值元素的相对排序。
// 基于 ["!", "Food", "Good", "Hi", "Animal", "Nice"] 排序
IntArray.StableSort([](const FString& A, const FString& B){
return A.Len() < B.Len();
}) // ==> ["?", "Hi", "Food", "Good", "Nice", "Animal"]
查
- 容器操作
// IntArray == [3,6,2,1,8]
// 使用 Num 得到数组的元素数量
int32 Nums = IntArray.Num(); // 目前存了5个元素 ==> Nums == 5
// 使用 GetSlack 找出数组中的Slack量,相当于Max()-Num()
int32 Max = IntArray.Max(); // 目前总共能存22个元素 ==> Max == 22
int32 Slack = IntArray.GetSlack(); // 目前还能存17个元素 ==> Slack == 17
// 使用 Shrink 移除所有Slack。
IntArray.Shrink();
int32 Nums = IntArray.Num(); // ==> Nums == 5
int32 Slack = IntArray.GetSlack(); // ==> Slack == 5
// 使用 GetTypeSize 获取单个元素的大小
uint32 ElementSize = IntArray.GetTypeSize(); // ==> ElementSize == sizeof(uint32)
// 使用 [] 输入元素索引得到元素值
int32 Value = IntArray[2]; // ==> Value == 2
// 使用 Last 反向索引
// StrArr.Top() == StrArr.Last() == StrArr.Last(0)
int32 ElemEndA = StrArr.Last(); // ==> ElemEndA == 8
int32 ElemEndB = StrArr.Last(0);// ==> ElemEndA == 8
int32 ElemEndC = StrArr.Last(1);// ==> ElemEndA == 1
// 使用 Top 得到数组最后一个元素
int32 ElemTop = StrArr.Top(); // ==> ElemEndA == 8
// 当索引小于零或大于等于Num()时,为无效索引,会引起运行时错误。可以使用 IsValidIndex 函数来确定索引是否有效。
bool bIsValid = IntArray.IsValidIndex(-1); // ==> bIsValid == false
bool bIsValid = IntArray.IsValidIndex(2); // ==> bIsValid == true
bool bIsValid = IntArray.IsValidIndex(6); // ==> bIsValid == false
// 判断TArray是否包含某个特定元素,使用 Contains:
bool bIsContain = IntArray.Contains(1); // ==> bIsValid == true
bool bIsContain = IntArray.Contains(4); // ==> bIsValid == false
// 使用 ContainsByPredicate 可以用 Lambda表达式 来判断是否包含具有某些特征的元素。
bool bIsContainByPredicate = IntArray.ContainsByPredicate([](const int32& Num){Num % 2 == 0}) // 存在偶数 ==> true
// 使用 Find 查找某个元素是否存在并返回其索引,FindLast从后往前查找。
int32 Index = IntArray.Find(1); // ==> Index == 3
int32 Index = IntArray.FindLast(1); // ==> Index == 1
int32 Index = IntArray.Find(5); // ==> Index == INDEX_NONE
// 使用 IndexOfByKey 与 Find 类似。
int32 Index = IntArray.IndexOfByKey(1); // ==> Index == 3
int32 Index = IntArray.IndexOfByKey(5); // ==> Index == INDEX_NONE
// 使用 IndexOfByPredicate 可以使用 Lambda表达式 来查找具有某些特征的元素。
int32 Index = IntArray.IndexOfByPredicate([](const int32& Num){Num % 2 == 0}) // 第一个偶数的索引 ==> index == 1
// 使用 FindByKey 可以返回找到的元素的指针
auto* Ptr = IntArray.FindByKey(1); // ==> Ptr == &IntArray[3]
// 使用 FindByPredicate 可以使用 Lambda表达式 来查找具有某些特征的元素的指针。
auto* Ptr = IntArray.FindByPredicate([](const int32& Num){Num % 2 == 0}) // ==> Ptr == &IntArray[1]
// 使用 FilterByPredicate 将会返回一个具有某个特征的元素数组。
auto Filter = IntArray.FilterByPredicate([](const int32& Num){Num % 2 == 0}) // ==> Filter == [6, 2, 8]
- Find 和 IndexOfByKey 源码比较如下。
// Find是将数组元素转换成你传入的类型在和你传入的数据进行比较。
// IndexOfByKey是直接将数组元素与你传入的数据进行比较。
// Find 函数源码 :
SizeType Find(const ElementType& Item) const
{
const ElementType* RESTRICT Start = GetData();
for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data)
{
if (*Data == Item)
{
return static_cast<SizeType>(Data - Start);
}
}
return INDEX_NONE;
}
// IndexOfByKey 函数源码 :
template <typename KeyType>
SizeType IndexOfByKey(const KeyType& Key) const
{
const ElementType* RESTRICT Start = GetData();
for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Start + ArrayNum; Data != DataEnd; ++Data)
{
if (*Data == Key)
{
return static_cast<SizeType>(Data - Start);
}
}
return INDEX_NONE;
}
- 遍历操作。(注意:遍历时不要做删除操作)
// 基于索引的for循环遍历
for (int32 Index = 0; Index != IntArray.Num(); ++Index)
{
IntArray[Index]; // 遍历的值
}
// auto遍历
for (auto& Int : IntArray)
{
Int; // 遍历的值
}
// 迭代器遍历
// CreateIterator 返回拥有读写访问权限的迭代器,
// CreateConstIterator 返回拥有只读访问权限的迭代器
for (auto It = IntArray.CreateConstIterator(); It; ++It)
{
*It; // 遍历的值
}
堆
- TArray 拥有支持二叉堆数据结构的函数。
// IntArray == [1,2,3,4,5,6,7,8,9,10]
// 使用 Heapify 将现有数组转换为堆
IntArray.Heapify(); // ==> IntArray == [1,2,4,3,6,5,8,10,7,9]
// 使用 HeapPush 将新元素添加到堆,对其他节点进行重新排序。
IntArray.HeapPush(4); // ==> IntArray == [1,2,4,3,4,5,8,10,7,9,6]
// 使用 HeapPop 移除堆顶结点。
int32 TopNode;
IntArray.HeapPop(TopNode); // ==> TopNode == 1; IntArray == [2,3,4,6,4,5,8,10,7,9]
// 使用 HeapRemoveAt 删除数组中给定索引处的元素,然后重新排列元素。
IntArray.HeapRemoveAt(1); // ==> IntArray == [2,4,4,6,9,5,8,10,7]
// 使用 HeapTop 查看堆的顶部节点,无需变更数组。
int32 Top = IntArray.HeapTop(); // ==> Top == 2
TMap
- TMap 是虚幻C++中的散列容器,主要由一个键类型和一个值类型,以关联对
TPair<KeyType, ValueType>
的形式存储在映射中。 - 键类型必须支持 GetTypeHash 函数,并提供运算符 == 来比较各个键是否等值。
- TMap 也可使用任选分配器来控制内存分配行为。
初始化
TMap<int32, FString> FoodMap; //空
- 使用结构体当作Key。
// 声明结构体,定义操作符 == 和函数 GetTypeHash。
USTRUCT(BlueprintType)
struct FMyStruct
{
GENERATED_USTRUCT_BODY()
EMyEnum EnumA;
EMyEnum EnumB;
friend inline bool operator==(const FMyStruct& A, const FMyStruct& B)
{
return A.EnumA == B.EnumA && A.EnumB == B.EnumB;
}
friend inline uint32 GetTypeHash(const FMyStruct& C)
{
uint32 Hash = 0;
Hash = HashCombine(Hash, GetTypeHash(C.EnumA));
Hash = HashCombine(Hash, GetTypeHash(C.EnumB));
return Hash;
}
};
// 使用 FMyStruct 当 Key。但是不支持蓝图了。
TMap<FMyStruct, FString> MyMap;
增
TMap<int32, FString> FoodMapA;
// 使用 Add 或 Emplace 添加元素
// 与 TArray 类似,Emplace 可以避免创建不必要的临时变量,效率比 Add 高。
// 各个键都必定是唯一。
// 如果尝试添加重复键,将替换原来的键值。
FoodMapA.Add(3, TEXT("Banana"));
FoodMapA.Add(6, TEXT("Apple"));
/** 当前TMap为:
* FoodMapA == [
* { Key:3, Value:"Banana"},
* { Key:6, Value:"Apple" }]
*/
FoodMapA.Add(3, TEXT("Orange"));
FoodMapA.Emplace(7, TEXT("Cake"));
/** 当前TMap为:
* FoodMapA == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
// 使用 Append 函数合并映射,将一个映射的所有元素移至另一个映射。
// Apeend的Map映射的相同键会替代原映射中的键。
/** 存在一个TMap为:
* FoodMapB == [
* { Key:3, Value:"Sweet"},
* { Key:1, Value:"Water" }
* { Key:9, Value:"Cola" }]
*/
FoodMapA.Append(FoodMapB);
/** 当前TMap为:
* FoodMapA == [
* { Key:3, Value:"Sweet"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" },
* { Key:1, Value:"Water" },
* { Key:9, Value:"Cola" }]
*/
删
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
// 使用 Remove 函数移除元素。
// 移除元素将在数据结构中留下空位。
FoodMap.Remove(6);
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* <invalid>,
* { Key:7, Value:"Cake" }]
*/
// 使用 FindAndRemoveChecked 函数可用于从映射移除元素并返回其值,不存在,则出现断言。
FString RemovedStr = FoodMap.FindAndRemoveChecked(7); // ==> RemovedStr == Cake
FString RemovedStr = FoodMap.FindAndRemoveChecked(7); // ==> Assert
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* <invalid>,
* <invalid>]
*/
// 使用 RemoveAndCopyValue 函数的作用与 Remove 相似,不同点是会将已移除元素的值复制到引用。
// 如果映射中不存在指定的键,函数将返回 false。
FString RemovedStrA;
bool bExistA = FoodMap.RemoveAndCopyValue(3, RemovedStrA); // ==> bExistA == true; RemovedStrA == "Orange"
/** 当前TMap为:
* FoodMap == [
* <invalid>,
* <invalid>,
* <invalid>]
*/
FString RemovedStrB;
bool bExistB = FoodMap.RemoveAndCopyValue(1, RemovedStrB); // ==> bExistB == false; RemovedStrB == ""
/** 当前TMap为:
* FoodMap == [
* <invalid>,
* <invalid>,
* <invalid>]
*/
// 使用 Empty 或 Reset 函数可将映射中的所有元素移除。
// Reset 则是尽可能多地留出slack量。
FoodMap.Empty();
/** 当前TMap为:
* FoodMap == [
* <invalid>,
* <invalid>,
* <invalid>]
*/
FoodMap.Reset();
/** 当前TMap为:
* FoodMap == []
*/
改
- 运算符。
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
// 使用 [] 去更改值。
FoodMap[7] = TEXT("Cola");
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cola" }]
*/
// 使用 MoveTemp 函数可调用移动语义,在移动后,源映射为空。
TMap<int32, FString> NewFoodMap;
NewFoodMap = MoveTemp(FoodMap);
/** 当前TMap为:
* NewFoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cola" }]
* FoodMap == []
*/
- 排序。
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
// 使用 KeySort 或 ValueSort 函数可分别按键和值进行排序,皆可使用Lambda谓语。
FoodMap.KeySort([](int32 A, int32 B) {
return A > B;
});
/** 当前TMap为:
* FoodMap == [
* { Key:7, Value:"Cake" },
* { Key:6, Value:"Apple" },
* { Key:3, Value:"Orange"}]
*/
FruitMap.ValueSort([](const FString& A, const FString& B) {
return A.Len() > B.Len();
});
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
- 内存。
TMap<int32, FString> FoodMap;
/** 当前TMap为:
* FoodMap == []
*/
// 使用 Reserve 函数预先分配映射
FoodMap.Reserve(3);
/** 当前TMap为:
* FoodMap == [
* <invalid>,
* <invalid>,
* <invalid>]
*/
// 使用 Shrink 函数可移除 TMap 中的全部 Slack。
FoodMap.Shrink();
/** 当前TMap为:
* FoodMap == []
*/
// Shrink 将从容器的末端移除所有Slack,通常会留下空白元素。
// 使用 Compact 函数将空白空间组合在一起,为调用 Shrink 做好准备。
/** 假设当前TMap为:
* FoodMap == [
* <invalid>,
* { Key:3, Value:"Orange"},
* <invalid>,
* { Key:6, Value:"Apple" },
* <invalid>,
* { Key:7, Value:"Cake" }
* <invalid>]
*/
FoodMap.Shrink();
/** 当前TMap为:
* FoodMap == [
* <invalid>,
* { Key:3, Value:"Orange"},
* <invalid>,
* { Key:6, Value:"Apple" },
* <invalid>,
* { Key:7, Value:"Cake" }]
*/
FoodMap.Compact();
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" },
* <invalid>,
* <invalid>,
* <invalid>]
*/
FoodMap.Shrink();
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
查
/** 当前TMap为:
* FoodMap == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"Cake" }]
*/
// 使用 Num 函数查询映射中保存的元素数量。
int32 Count = FoodMap.Num(); // ==> Count == 3
// 使用 Contains 函数查询是否包含特定键。
bool bHas = FoodMap.Contains(7); // ==> bHas == true
bool bHas = FoodMap.Contains(1); // ==> bHas == false
// 使用 [] 运算符将键用作索引查找相应值。
// 在使用运算符 [] 前,应检查映射中是否 Contains 该键,如果映射中键不存在,将触发断言。
FString Str = FoodMap[7]; // ==> Str == "Cake"
// 使用 Find 函数进行键查找,
// 如果映射包含该键,Find 将返回指向元素数值的指针,如果映射不包含该键,则返回 nullptr。
FString* Str = FoodMap.Find(7); // ==> *Str == "Cake"
FString* Str = FoodMap.Find(10); // ==> Str == nullptr
// 使用 FindOrAdd 将返回给定键的值引用。
// 如果映射中不存在该键,FindOrAdd 将返回新创建的元素。
// FindOrAdd 可修改映射,因此仅适用于非常量映射。
FString& Str = FoodMap.FindOrAdd(7);
Str = "";
FString& Str = FoodMap.FindOrAdd(8);
Str = "Cake";
/** 当前TMap为:
* FoodMapA == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"" },
* { Key:8, Value:"Cake" },]
*/
// 使用 FindRef 会返回与给定键关联的值副本。
// 若映射中未找到给定键,则返回默认构建值。
// FindRef 不会创建新元素,因此既可用于常量映射,也可用于非常量映射。
FString Str = FoodMap.FindRef(8); // ==> Str == "Cake"
Str = TEXT("Apple"); // ==> Str == "Apple"
/** 当前TMap为:
* FoodMapA == [
* { Key:3, Value:"Orange"},
* { Key:6, Value:"Apple" },
* { Key:7, Value:"" },
* { Key:8, Value:"Cake" },]
*/
// 使用 FindKey 函数执行逆向查找。
// 返回指向提供值配对的第一个键的指针,搜索映射中不存在的值将返回空键。
// 按值查找比按键查找慢。
const int32* KeyA = FoodMap.FindKey(TEXT("Apple")); // *KeyA == 6
const int32* KeyB = FoodMap.FindKey(TEXT("Cola")); // KeyB == nullptr
// 使用 GenerateKeyArray 和 GenerateValueArray 分别使用所有键和值的副本来填充到 TArray。
TArray<int32> FoodKeys;
TArray<FString> FoodValues;
FoodMap.GenerateKeyArray(FoodKeys);
FoodMap.GenerateValueArray(FoodValues);
// FoodKeys == [ 3,6,7,8 ]
// FoodValues == [ "Orange","Apple","Pineapple","Cake" ]
- 遍历操作。(注意:遍历时不要做删除操作)
// auto 遍历
for (auto& Elem :FoodMap)
{
Elem.Key; // Map的Key
Elem.Value; // Map的Value
}
// 迭代器遍历
// CreateIterator 返回拥有读写访问权限的迭代器,
// CreateConstIterator 返回拥有只读访问权限的迭代器
for (auto It = FoodMap.CreateConstIterator(); It; ++It)
{
It.Key(); // Map的Key
It.Value(); // Map的Value
}
TSet
- TSet 是一种快速容器类,使用数据值本身作为键。
初始化
TSet<FString> FoodSet;
增
// 使用 Add 或 Emplace 添加元素。
FoodSet.Add(TEXT("Banana"));
FoodSet.Add(TEXT("Apple"));
FoodSet.Emplace(TEXT("Orange"));
// ==> FoodSet == [ "Banana", "Apple", "Orange" ]
// 使用 Append 函数来插入另一个集合中的所有元素。
// 存在 NewFoodSet == [ "Cake", "Cola", "Orange" ]
FoodSet.Append(NewFoodSet);
// ==> FoodSet == [ "Banana", "Apple", "Orange", "Cake", "Cola" ]
删
// 存在 FoodSet == [ "Banana", "Apple", "Orange", "Cake", "Cola" ]
// 使用 Remove 函数可按索引移除元素。
int RemovedCount = FoodSet.Remove(TEXT("Apple")); // ==> RemovedCount == 1
// ==> FoodSet == [ "Banana", <invalid>, "Orange", "Cake", "Cola" ]
int RemovedCount = FoodSet.Remove(TEXT("Apple")); // ==> RemovedCount == 0
// ==> FoodSet == [ "Banana", <invalid>, "Orange", "Cake", "Cola" ]
// 使用 Empty 或 Reset 函数可将集合中的所有元素移除。
FoodSet.Reset();
// ==> FoodSet == [ <invalid>, <invalid>, <invalid>, <invalid>, <invalid> ]
FoodSet.Empty();
// ==> FoodSet == []
改
- 排序。
// 存在 FoodSet == [ "Apple", "Orange", "Cake", ]
FoodSet.Sort([](const FString& A, const FString& B) {
return A > B;
});
// ==> FoodSet == [ "Apple", "Cake", "Orange"]
FoodSet.Sort([](const FString& A, const FString& B) {
return A.Len() > B.Len();
});
// ==> FoodSet == [ "Orange", "Apple", "Cake"]
- 内存
// 使用 Reserve 函数可直接创建 slack,在添加元素之前预分配内存。
TSet<int32> IntSet;
IntSet.Reserve(4); // ==> IntSet == [ <invalid>, <invalid>, <invalid>, <invalid> ]
// 使用 Shrink 函数可移除 TSet 中的全部 slack。
IntSet.Shrink(); // ==> IntSet == []
// 存在 FoodSet == [ "Apple", <invalid>, "Orange", <invalid>, "Cake", <invalid>]
// 使用 Compact 或 CompactStable 函数,将空白空间组合在一起,为调用 Shrink 做好准备。
FoodSet.Shrink(); // ==> IntSet == [ "Apple", <invalid>, "Orange", <invalid>, "Cake"]
FoodSet.Compact(); // ==> IntSet == [ "Apple", "Orange", "Cake", <invalid>, <invalid>]
FoodSet.Shrink(); // ==> IntSet == [ "Apple", "Orange", "Cake" ]
查
// 存在 FoodSet == [ "Banana", "Apple", "Orange", "Cake", "Cola"]
// 使用 Num 函查询集合中保存的元素数量。
int32 Count = FoodSet.Num(); // ==> Count == 5
// 使用 Contains 函数查询是否包含特定元素。
bool bContains = FoodSet.Contains(TEXT("Banana")); // ==> bContains == true
bool bContains = FoodSet.Contains(TEXT("Water")); // ==> bContains == false
// 使用 FSetElementId 结构体可查找集合中某个键的索引。
// 使用运算符 [] 查找元素。
FSetElementId Index = FoodSet.Index(TEXT("Banana")); // ==> FoodSet[Index] == TEXT("Banana")
FSetElementId Index = FoodSet.Index(TEXT("Water")); // ==> FoodSet[Index] Assert
// 使用 Find 返回指向元素数值的指针。
FString* Ptr = FoodSet.Find(TEXT("Banana")); // ==> *Ptr == TEXT("Banana")
FString* Ptr = FoodSet.Find(TEXT("Water")); // ==> Ptr == nullptr
// 使用 Array 函数会返回一个 TArray,其中填充了 TSet 中每个元素的一份副本。
TArray<FString> FoodArray = FoodSet.Array();
// FoodArray == [ "Banana","Apple","Orange","Cake","Cola" ]
- 遍历
// auto遍历。
for (auto& Elem : FoodSet)
{
Elem; // 遍历的值。
}
// 迭代器遍历。
// CreateIterator 返回拥有读写访问权限的迭代器,
// CreateConstIterator 返回拥有只读访问权限的迭代器
for (auto It = FoodSet.CreateConstIterator(); It; ++It)
{
*it; // 遍历的值。
}
运算
// 存在 FoodSetA == [ "Orange", "Apple", "Cake"]
// 存在 FoodSetB == [ "Banana", "Apple", "Cola"]
// 使用 Intersect 求交集。
TSet<FString> FoodSetC = FoodSetA.Intersect(FoodSetB); // ==> FoodSetC == [ "Apple" ]
// 使用 Union 求并集。
TSet<FString> FoodSetD = FoodSetA.Union(FoodSetB); // ==> FoodSetD == [ "Orange", "Apple", "Cake", "Banana", "Cola" ]
// 使用 Difference 求差集,返回 this set 不在 other set 里的集合。
TSet<FString> FoodSetE = FoodSetA.Difference(FoodSetB); // A不在B里 ==> FoodSetD == [ "Orange", "Cake" ]
TSet<FString> FoodSetF = FoodSetB.Difference(FoodSetA); // B不在A里 ==> FoodSetD == [ "Banana", "Cola" ]
// 存在 IntSetA == [ 1,2,3,4 ]
// 存在 IntSetB == [ 1,2,3,4,5,6,7,8,9 ]
// 使用 Includes 计算 this set 是否包含 other set。
bool Includes = IntSetA.Includes(IntSetB); // ==> Includes == false
bool Includes = IntSetB.Includes(IntSetA); // ==> Includes == true
补充 TMultiMap
- 允许键重复,不能用 UPROPERTY 标记。
- 否则会报错:
Unrecognized type 'TMultiMap' - type must be a UCLASS, USTRUCT or UENUM
- 否则会报错:
TMultiMap<int32, FString> multiMap;
// 使用 Add 添加元素。
multiMap.Add(1, TEXT("苹果"));
/** 当前TMap为:
* FoodMap == [
* { Key:1, Value:"苹果"}]
*/
multiMap.Add(1, 456);
/** 当前TMap为:
* FoodMap == [
* { Key:1, Value:"苹果"},
* { Key:1, Value:"香蕉" }]
*/
// 使用 Emplace 添加元素。
multiMap.Emplace(2, TEXT("电脑"));
multiMap.Emplace(2, TEXT("平板"));
multiMap.Emplace(2, TEXT("手机"));
/** 当前TMap为:
* FoodMap == [
* { Key:1, Value:"苹果"},
* { Key:1, Value:"香蕉" },
* { Key:2, Value:"电脑" },
* { Key:2, Value:"平板" },
* { Key:2, Value:"手机" }]
*/
// 使用 Remove 会移除所有重复键元素。
multiMap.Remove(333);
/** 当前TMap为:
* FoodMap == [
* { Key:2, Value:"电脑" },
* { Key:2, Value:"平板" },
* { Key:2, Value:"手机" }]
*/
// 使用 Remove 依据键和值,移除指定元素。
multiMap.Remove(2, TEXT("电脑"));
/** 当前TMap为:
* FoodMap == [
* { Key:2, Value:"平板" },
* { Key:2, Value:"手机" }]
*/
// 使用 RemoveSingle 与 Remove一样。
multiMap.RemoveSingle(2, TEXT("手机"));
/** 当前TMap为:
* FoodMap == [
* { Key:2, Value:"平板" }]
*/
// 使用 FindPair 查找元素,因为键可重复,所以需要指定值才能找到数据。
int* ptr = multiMap.FindPair(2, TEXT("平板"));