TMap
TMap:用于存储 键值对 数据。类似于字典或哈希表,每个元素由一个唯一的“键”(Key)和与之关联的“值”(Value)组成。
UE中有两种Map:TMap
和 TMultiMap
。TMap
中的键是唯一的,TMultiMap
可存储多个相同的键。
TMap
添加新的键值时,如果键已存在,新对将替换原有的对。在 TMultiMap
中,容器可以同时存储新对和原有的对。
一、创建
TMap
是同质容器,所有元素的类型都相同
TMap<int32, FString> FruitMap;
二、填充
1、Add()
:填充键值对
Add()
为TMap
添加重复键时,会替代原来的value
。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:""},
// ]
2、Emplace()
:填充键值对(原地创建)
同TArray
一样,Emplace()
与Add()
区别在于插入映射时不创建临时文件
3、Append()
:填充其他TMap
中的多个键值对
Append()
的过程就是一个个的Add()
,因此如果被填充的TMap如果与填充的TMap有相同的Key,则会被替代为新的键值对
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:9, Value:Melon },
// ]
三、迭代
// auto 范围遍历
for (auto& Elem : FruitMap)
{
Elem.Key..;
Elem.Value..;
}
// 迭代器迭代
for (auto Iter = FruitMap.CreateIterator(); Iter; ++Iter) // CreateConstIterator 只读迭代器
{
Iter.Key...;
Iter.Value...;
}
四、查询
1、Num()
:查询Map键值对个数
int32 Count = FruitMap.Num(); // Count = 5
2、Contanis()
:查询是否包含某个键
bool bHas7 = FruitMap.Contains(7); // bHas7 = true
bool bHas8 = FruitMap.Contains(8); // bHas8 = false
3、[]
、Find()
和FindRef()
:查找某个键对应的值
[]
:返回所查找键对应值的引用,如果不存在该键,报错
Find()
:返回所查找键对应值的指针,如果不存在该键,返回nullptr
FindRef
会返回与给定键关联的值副本;若映射中未找到给定键,返回默认构建值。
FString Val7 = FruitMap[7]; // Val7 = Pineapple
FString Val7 = FruitMap[8]; // 报错
FString* Ptr7 = FruitMap.Find(7); // Ptr7 = 指向"Pineapple"这个值的指针
FString* Ptr8 = FruitMap.Find(8); // Ptr8 = nullptr
FString Str7 = FruitMap.FindRef(7); // Str7 = Pineapple
FString Str8 = FruitMap.FindRef(8); // Str8 = Empty
4、FindOrAdd()
:查找或添加某个键
FindOrAdd()
返回所查找键对应值的引用,如果不存在该键,返回新创建的元素。
FString& Ref7 = FruitMap.FindOrAdd(7); // Ref7 = Pineapple
FString& Ref8 = FruitMap.FindOrAdd(8); // Ref8 = Empty
Ref8 = TEXT("Peach");
// FruitMap = [
// { Key:5, Value:Mango },
// { Key:2, Value:Pear },
// { Key:7, Value:Pineapple1 },
// { Key:4, Value:Kiwi },
// { Key:9, Value:Melon },
// { Key:8, Value:Peach },
// ]
5、FindKey()
:查找某个值对应的键
FindKey()
:返回所查找到第一个值对应键的指针,如果不存在该值,返回空键
- 按值查找比按键查找慢(线性时间)。因为映射按键排序,而非按值排序。
- 如果映射有多个具有相同值的键,
FindKey
可返回其中任一键。
const int32* KeyMangoPtr = FruitMap.FindKey(TEXT("Mango")); // KeyMangoPtr = 指向键5的指针
const int32* KeyKumquatPtr = FruitMap.FindKey(TEXT("Kumquat")); // KeyKumquatPtr = nullptr
6、GenerateKeyArray()
和GenerateValueArray()
:使用键和值的副本填充TArray
- 两个方法在填充前都会清空所传递的数组
TArray<int32> FruitKeys;
TArray<FString> FruitValues;
FruitKeys.Add(999);
FruitKeys.Add(123);
FruitMap.GenerateKeyArray(FruitKeys); // FruitKeys = [5, 2, 7, 4, 9, 8]
FruitMap.GenerateValueArray(FruitValues); // FruitValues = [Mango, Pear, Pineapple1, Kiwi, Melon, Peach]
五、移除
1、Remove()
:移除特定键对应的键值对
Remove()
会移除指定键对应的键值对,并返回被移除元素的数量,如果不存在该键,则返回0
Count = FruitMap.Remove(8); // Count = 1
2、FindAndRemoveChecked()
:移除特定键对应键值对,并返回值
移除元素并返回其值,如果键不存在,则会报错
FString Removed7 = FruitMap.FindAndRemoveChecked(7); // Removed7 = Pineapple1
FString Removed8 = FruitMap.FindAndRemoveChecked(8); // 报错
3、RemoveAndCopyValue()
:移除特定键对应键值对,并返回值
移除元素并将对应值复制到引用参数,如果键不存在,引用参数不变,函数返回false
FString Removed;
bool bFound2 = FruitMap.RemoveAndCopyValue(2, Removed); // bFound2 = true ; Removed = Pear
bool bFound8 = FruitMap.RemoveAndCopyValue(8, Removed); // bFound8 = false ; Removed = Pear
4、Empty()
和Reset()
:移除所有键值对
同TArray
一样,Reset()
方法不会释放先前的内存。
六、排序
1、KeySort()
:按键排序
2、ValueSort()
:按值排序
- 排序后,迭代映射会以排序的顺序显示元素
- 再次修改映射时,排序可能会发生变化
- 排序是不稳定的,等值元素在
MultiMap
中可能以任何顺序出现。
FruitMap.KeySort([](int32 A, int32 B) {
return A > B;
});
// FruitMap == [
// { Key:9, Value:"Melon" },
// { Key:5, Value:"Mango" },
// { Key:4, Value:"Kiwi" },
// ]
FruitMap.ValueSort([](const FString& A, const FString& B) {
return A.Len() < B.Len();
});
// FruitMap == [
// { Key:4, Value:"Kiwi" },
// { Key:5, Value:"Mango" },
// { Key:9, Value:"Melon" },
// ]
七、运算符
1、赋值运算符=
同TArray
一样,是一次深拷贝
2、MoveTemp
同TArray
一样,支持移动语义MoveTemp
,移动后,源映射为空
八、Slack(空闲容量)
1、Reverse()
:分配内存
同TArray
一样,分配内存,无需添加元素,如果分配的内存比当前小,则无效。
2、Shrink()
和Compact()
:移除所有Slack
Shrink()
将从容器的末端移除所有slack,如果映射中间存在slack则无法移除,首先应调用 Compact()
函数,将空白空间组合在一起,再调用Shrink()
九、KeyFuncs
只要类型具有 运算符==
和非成员 GetTypeHash
重载,就可用作 TMap
的键类型,不需要任何更改。但是,您可能需要将类型用作键,而不重载这些函数。在这些情况下,可对 KeyFuncs
进行自定义。为键类型创建 KeyFuncs
,必须定义两个typedef和三个静态函数,如下所示:
KeyInitType
—— 用于传递键的类型。ElementInitType
—— 用于传递元素的类型。KeyInitType GetSetKey(ElementInitType Element)
——返回元素的键。bool Matches(KeyInitType A, KeyInitType B)
—— 如果A
和B
等值将返回true
,否则返回false
。uint32 GetKeyHash(KeyInitType Key)
—— 返回Key
的散列值。
struct FMyStruct // 作为TMap Key的结构体
{
// String which identifies our key
FString UniqueID;
// Some state which doesn't affect struct identity
float SomeFloat;
explicit FMyStruct(float InFloat)
:UniqueID (FGuid::NewGuid().ToString())
, SomeFloat(InFloat)
{
}
};
template <typename ValueType>
struct TMyStructMapKeyFuncs : BaseKeyFuncs<TPair<FMyStruct, ValueType>, FString> // 自定义KeyFuncs
{
private:
typedef BaseKeyFuncs<TPair<FMyStruct, ValueType>, FString> Super;
public:
typedef typename Super::ElementInitType ElementInitType; // 用于传递元素的类型
typedef typename Super::KeyInitType KeyInitType; // 用于传递键的类型
static KeyInitType GetSetKey(ElementInitType Element) // 返回元素的键
{
return Element.Key.UniqueID;
}
static bool Matches(KeyInitType A, KeyInitType B) // 如果 A 和 B 等值将返回 true,否则返回 false
{
return A.Compare(B, ESearchCase::CaseSensitive) == 0;
}
static uint32 GetKeyHash(KeyInitType Key) // 返回 Key 的散列值。
{
return FCrc::StrCrc32(*Key);
}
};
TMap<FMyStruct, int32, FDefaultSetAllocator, TMyStructMapKeyFuncs<int32>> MyMapToInt32;
// Add some elements
MyMapToInt32.Add(FMyStruct(3.14f), 5);
MyMapToInt32.Add(FMyStruct(1.23f), 2);