UE5 C++ TMap
概述
- 映射的元素类型为键值对,元素类型实际上是
TPair<KeyType, ElementType>
,只将键用于存储和获取 TMap
和TMultiMap
两者之间的不同点是TMap
中的键是唯一的,而TMultiMap
可存储多个相同的键TMap
是散列容器,这意味着键类型必须支持GetTypeHash
函数,并提供运算符==
来比较各个键是否等值
创建
TMap<int32, FString> FruitMap;
添加元素
-
Add
函数- 添加重复键,覆盖已有的
- 可接受不带值的键,调用此重载后的 Add 时,值将被默认构建:
FruitMap.Add(5, TEXT("Banana")); FruitMap.Add(2, TEXT("Grapefruit")); FruitMap.Add(7, TEXT("Pineapple")); // FruitMap == [ // { Key:5, Value:"Banana" }, // { Key:2, Value:"Grapefruit" }, // { Key:7, Value:"Pineapple" } // ] FruitMap.Add(2, TEXT("Pear")); // FruitMap == [ // { Key:5, Value:"Banana" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" } // ] FruitMap.Add(4); // FruitMap == [ // { Key:5, Value:"Banana" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"" } // ]
-
Emplace
代替Add
,防止插入映射时创建临时文件FruitMap.Emplace(3, TEXT("Orange")); // FruitMap == [ // { Key:5, Value:"Banana" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"" }, // { Key:3, Value:"Orange" } // ]
-
Append
函数合并映射,将一个映射的所有元素移至另一个映射TMap<int32, FString> FruitMap2; FruitMap2.Emplace(4, TEXT("Kiwi")); FruitMap2.Emplace(9, TEXT("Melon")); FruitMap2.Emplace(5, TEXT("Mango")); FruitMap.Append(FruitMap2); // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ] // FruitMap2 is now empty.
迭代
-
范围 for-range
for (auto& Elem :FruitMap) { FPlatformMisc::LocalPrint( *FString::Printf( TEXT("(%d, \"%s\")\n"), Elem.Key, *Elem.Value ) ); } // Output: // (5, "Mango") // (2, "Pear") // (7, "Pineapple") // (4, "Kiwi") // (3, "Orange") // (9, "Melon")
-
迭代器
- CreateIterator 返回拥有读写访问权限的迭代器
- CreateConstIterator 返回拥有只读访问权限的迭代器
for (auto It = FruitMap.CreateConstIterator(); It; ++It) { FPlatformMisc::LocalPrint( *FString::Printf( TEXT("(%d, \"%s\")\n"), It.Key(), // same as It->Key *It.Value() // same as *It->Value ) ); }
查询
-
Num
函数查询map中保存的元素数量int32 Count = FruitMap.Num(); // Count == 6
-
Contains
函数确定映射是否包含特定键bool bHas7 = FruitMap.Contains(7); // bHas7 == true bool bHas8 = FruitMap.Contains(8); // bHas8 == false
-
运算符
[]
获取特定键对应的值FString Val7 = FruitMap[7]; // Val7 == "Pineapple" FString Val8 = FruitMap[8]; // Assert!
-
Find
返回指向特定键对应值的指针,如果map不包含该键,则返回nullptrFString* Ptr7 = FruitMap.Find(7); // *Ptr7 == "Pineapple" FString* Ptr8 = FruitMap.Find(8); // Ptr8 == nullptr
-
FindOrAdd
将返回对与给定键关联的值的引用- 如果映射中不存在该键,FindOrAdd 将返回新创建的元素(使用给定键和默认构建值),该元素也会被添加到映射
- 仅适用于非常量映射
-
FindRef
会返回与给定键对应值的副本- 若映射中未找到给定键,则返回默认构建值
- 不会创建新元素,因此既可用于常量映射,也可用于非常量映射
FString& Ref7 = FruitMap.FindOrAdd(7); // Ref7 == "Pineapple" // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ] FString& Ref8 = FruitMap.FindOrAdd(8); // Ref8 == "" // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" }, // { Key:8, Value:"" } // ] FString Val7 = FruitMap.FindRef(7); FString Val6 = FruitMap.FindRef(6); // Val7 == "Pineapple" // Val6 == "" // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" }, // { Key:8, Value:"" } // ]
-
FindKey
与Find
相对,其返回指向与所提供值配对的第一个键的指针,搜索映射中不存在的值将返回nullptr- 如果映射有多个具有相同值的键
- FindKey 可返回其中任一键
const int32* KeyMangoPtr = FruitMap.FindKey(TEXT("Mango")); // *KeyMangoPtr == 5 const int32* KeyKumquatPtr = FruitMap.FindKey(TEXT("Kumquat")); // KeyKumquatPtr == nullptr
-
GenerateKeyArray
使用所有键副本来填充 TArray -
GenerateValueArray
使用所有值的副本来填充 TArray -
在这两种情况下,都会在填充前清空所传递的数组,因此产生的元素数量始终等于映射中的元素数量
TArray<int32> FruitKeys; TArray<FString> FruitValues; FruitKeys.Add(999); FruitKeys.Add(123); FruitMap.GenerateKeyArray (FruitKeys); FruitMap.GenerateValueArray(FruitValues); // FruitKeys == [ 5,2,7,4,3,9,8 ] // FruitValues == [ "Mango","Pear","Pineapple","Kiwi","Orange", // "Melon","" ]
移除元素
Remove
函数移除指定键的元素- 返回值是被移除元素的数量
- 如果映射不包含与键匹配的元素,则返回值可为零
FruitMap.Remove(8); // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:7, Value:"Pineapple" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ]
FindAndRemoveChecked
函数可用于从map移除元素并返回其值- 若键不存在,映射将调用 check(UE4中等同于 assert)
FString Removed7 = FruitMap.FindAndRemoveChecked(7); // Removed7 == "Pineapple" // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:2, Value:"Pear" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ] FString Removed8 = FruitMap.FindAndRemoveChecked(8); // Assert!
RemoveAndCopyValue
的作用 与Remove
相似,不同点是会将已移除元素的值复制到引用参数- 如果映射中不存在指定的键,则输出参数将保持不变,函数将返回 false
FString Removed; bool bFound2 = FruitMap.RemoveAndCopyValue(2, Removed); // bFound2 == true // Removed == "Pear" // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ] bool bFound8 = FruitMap.RemoveAndCopyValue(8, Removed); // bFound8 == false // Removed == "Pear", i.e. unchanged // FruitMap == [ // { Key:5, Value:"Mango" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ]
Empty
或Reset
函数可将映射中的所有元素移除- Empty 可采用参数指示映射中保留的slack量
- Reset 则是尽可能多地留出slack量
TMap<int32, FString> FruitMapCopy = FruitMap; // FruitMapCopy == [ // { Key:5, Value:"Mango" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" }, // { Key:9, Value:"Melon" } // ] FruitMapCopy.Empty(); // We could also have called Reset() here. // FruitMapCopy == []
排序
KeySort
或ValueSort
函数可分别按键和值进行排序,两个函数均使用二元谓词来进行排序FruitMap.KeySort([](int32 A, int32 B) { return A > B; // sort keys in reverse }); // FruitMap == [ // { Key:9, Value:"Melon" }, // { Key:5, Value:"Mango" }, // { Key:4, Value:"Kiwi" }, // { Key:3, Value:"Orange" } // ] FruitMap.ValueSort([](const FString& A, const FString& B) { return A.Len() < B.Len(); // sort strings by length }); // FruitMap == [ // { Key:4, Value:"Kiwi" }, // { Key:5, Value:"Mango" }, // { Key:9, Value:"Melon" }, // { Key:3, Value:"Orange" } // ]
运算符
- 通过标准复制构造函数或赋值运算符进行复制,因为映射严格拥有其元素,复制映射的操作是深层的,所以新的映射将拥有其自己的元素副本
TMap<int32, FString> NewMap = FruitMap; NewMap[5] = "Apple"; NewMap.Remove(3); // FruitMap == [ // { Key:4, Value:"Kiwi" }, // { Key:5, Value:"Mango" }, // { Key:9, Value:"Melon" }, // { Key:3, Value:"Orange" } // ] // NewMap == [ // { Key:4, Value:"Kiwi" }, // { Key:5, Value:"Apple" }, // { Key:9, Value:"Melon" } // ]
MoveTemp
函数可调用移动语义
FruitMap = MoveTemp(NewMap);
// FruitMap == [
// { Key:4, Value:"Kiwi" },
// { Key:5, Value:"Apple" },
// { Key:9, Value:"Melon" }
// ]
// NewMap == []
Slack
- Slack是不包含元素的已分配内存
Reserve
可分配内存,无需添加元素- 通过非零slack参数调用
Reset
或Empty
可移除元素,无需将其使用的内存取消分配 - Slack优化了将新元素添加到映射的过程,因为可以使用预先分配的内存,而不必分配新内存
- 它在移除元素时也十分实用,因为系统不需要将内存取消分配
- 在清空希望用相同或更少的元素立即重新填充的映射时,此方法尤其有效
FruitMap.Reserve(10); for (int32 i = 0; i < 10; ++i) { FruitMap.Add(i, FString::Printf(TEXT("Fruit%d"), i)); } // FruitMap == [ // { Key:9, Value:"Fruit9" }, // { Key:8, Value:"Fruit8" }, // ... // { Key:1, Value:"Fruit1" }, // { Key:0, Value:"Fruit0" } // ]
- 使用
Collapse
和Shrink
函数可移除 TMap 中的全部slackShrink
将从容器的末端移除所有slack,但这会在中间或开始处留下空白元素
for (int32 i = 0; i < 10; i += 2) { FruitMap.Remove(i); } // FruitMap == [ // { Key:9, Value:"Fruit9" }, // <invalid>, // { Key:7, Value:"Fruit7" }, // <invalid>, // { Key:5, Value:"Fruit5" }, // <invalid>, // { Key:3, Value:"Fruit3" }, // <invalid>, // { Key:1, Value:"Fruit1" }, // <invalid> // ] FruitMap.Shrink(); // FruitMap == [ // { Key:9, Value:"Fruit9" }, // <invalid>, // { Key:7, Value:"Fruit7" }, // <invalid>, // { Key:5, Value:"Fruit5" }, // <invalid>, // { Key:3, Value:"Fruit3" }, // <invalid>, // { Key:1, Value:"Fruit1" } // ]
- 在上述代码中,Shrink 只删除了一个无效元素,因为末端只有一个空元素
- 要移除所有slack,首先应调用 Compact 函数,将空白空间组合在一起,为调用 Shrink 做好准备
FruitMap.Compact(); // FruitMap == [ // { Key:9, Value:"Fruit9" }, // { Key:7, Value:"Fruit7" }, // { Key:5, Value:"Fruit5" }, // { Key:3, Value:"Fruit3" }, // { Key:1, Value:"Fruit1" }, // <invalid>, // <invalid>, // <invalid>, // <invalid> // ] FruitMap.Shrink(); // FruitMap == [ // { Key:9, Value:"Fruit9" }, // { Key:7, Value:"Fruit7" }, // { Key:5, Value:"Fruit5" }, // { Key:3, Value:"Fruit3" }, // { Key:1, Value:"Fruit1" } // ]