目录
Append:合并映射,将一个映射的所有元素移至另一个映射,源映射的相同键会替代目标映射中的键
GenerateKeyArray和GenerateValueArray:分别使用所有键和值的副本来填充 TArray
FindAndRemoveChecked:可用于从映射移除元素并返回其值
RemoveAndCopyValue:与 Remove 相似,不同点是会将已移除元素的值复制到引用参数。如果映射中不存在指定的键,则输出参数将保持不变,函数将返回 false。
TMap主要由两个类型定义(一个键类型和一个值类型),以关联对的形式存储在映射中。
将数据存储为键值对(TPair),只将键用于存储和获取
映射有两种类型:TMap 和 TMultiMap
TMap 也是值类型,支持通常的复制、赋值和析构函数运算,以及它的元素的强所有权。在映射被销毁时,它的元素都会被销毁。键和值也必须为值类型。
TMap 是散列容器,这意味着键类型必须支持 GetTypeHash 函数,并提供 运算符== 来比较各个键是否等值
TMap 也可使用任选分配器来控制内存分配行为。但不同于 TArray,这些是集合分配器,而不是 FHeapAllocator 和 TInlineAllocator 之类的标准UE4分配器。集合分配器(TSetAllocator类)定义映射应使用的散列桶数量,以及应使用哪个标准UE4分配器来存储散列和元素。
KeyFuncs 是最后一个 TMap 模板参数,该参数告知映射如何从元素类型获取键,如何比较两个键是否相等,以及如何对键进行散列计算。这些参数有默认值,它们只会返回对键的引用,使用 运算符== 确定相等性,并调用非成员 GetTypeHash 函数进行散列计算。如果您的键类型支持这些函数,可使用它作为映射键,不需要提供自定义 KeyFuncs。
与 TArray 不同的是,内存中 TMap 元素的相对排序既不可靠也不稳定,对这些元素进行迭代很可能会使它们返回的顺序和它们添加的顺序有所不同。这些元素也不太可能在内存中连续排列。映射的支持数据结构是稀疏数组,这种数组可有效支持元素之间的空位。当元素从映射中被移除时,稀疏数组中就会出现空位。将新的元素添加到数组可填补这些空位。但是,即便 TMap 不会打乱元素来填补空位,指向映射元素的指针仍然可能失效,因为如果存储器被填满,又添加了新的元素,整个存储可能会重新分配。
TMap FruitMap; //空TMap,此时尚未分配内存
- 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:"" }
- // ]
- 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" }
- // ]
- TMap
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 (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")
- 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
- ) );
- }
int32 Count = FruitMap.Num(); // Count == 6
- 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!
- FString* Ptr7 = FruitMap.Find(7); // *Ptr7 == "Pineapple"
- FString* Ptr8 = FruitMap.Find(8); // Ptr8 == nullptr
- 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:"" }
- // ]
- //如已发生重新分配,此处的 Ref7 引用可能会因 FruitMap.FindOrAdd(8) 的调用而无效化。
- 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:"" }
- // ]
- const int32* KeyMangoPtr = FruitMap.FindKey(TEXT("Mango")); // *KeyMangoPtr == 5
- const int32* KeyKumquatPtr = FruitMap.FindKey(TEXT("Kumquat")); // KeyKumquatPtr == nullptr
- TArray
FruitKeys; - TArray
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","" ]
- 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" }
- // ]
- 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!
- 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" } ]
- TMap
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 == []
TMap 可以进行排序。排序后,迭代映射会以排序的顺序显示元素,但下次修改映射时,排序可能会发生变化。排序是不稳定的,因此等值元素在MultiMap中可能以任何顺序出现
使用 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" }
- // ]
和 TArray 一样,TMap 是常规值类型,可通过标准复制构造函数或赋值运算符进行复制。因为映射严格拥有其元素,复制映射的操作是深层的,所以新的映射将拥有其自己的元素副本。
- TMap
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 == []
参考链接: