【UEC++学习-UE容器之TMap】


TMap

TMap:用于存储 键值对 数据。类似于字典或哈希表,每个元素由一个唯一的“键”(Key)和与之关联的“值”(Value)组成。

UE中有两种Map:TMapTMultiMapTMap 中的键是唯一的,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) —— 如果 AB 等值将返回 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);

文章作者: Woilin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Woilin !
评论
  目录