一. 类介绍
继 TArray 之后,虚幻引擎4(UE4)中最常用的容器是 TMap。TMap 与 TSet 类似,它们的结构均基于对键进行散列运算。但与 TSet 不同的是,此容器将数据存储为键值对(TPair<KeyType, ValueType>)
,只将键用于存储和获取。
和 TArray 一样,TMap 也是同质容器,就是说它所有元素的类型都应完全相同。TMap 也是值类型,支持通常的复制、赋值和析构函数运算,以及它的元素的强所有权。在映射被销毁时,它的元素都会被销毁。键和值也必须为值类型。
映射有两种类型:TMap 和 TMultiMap。两者之间的不同点是,TMap 中的键是唯一的,而TMultiMap 可存储多个相同的键。在 TMap 中添加新的键值时,若所用的键与原有的对相同,新对将替换原有的对。在 TMultiMap
中,容器可以同时存储新对和原有的对。
是对 std::map/ std::multimap 的增强。
二. 创建TMap
TMap使用了c++的类模板的语法。
//FString,FString can be replaced with any data type
TMap<FString,FString>FStringMapFString;
三. TMap函数操作
1. 修改
FStringMapFString={};
//The unique key is to add
FStringMapFString.Add(TEXT("1"),TEXT("A"));
FStringMapFString.Add(TEXT("2"),TEXT("B"));
FStringMapFString.Add(TEXT("3"),TEXT("C"));
PRINTM(FStringMapFString);//[{Key:1,Value:A}{Key:2,Value:B}{Key:3,Value:C}]
//The duplicate key is to update
FStringMapFString.Add(TEXT("3"),TEXT("D"));
PRINTM(FStringMapFString);//[{Key:1,Value:A}{Key:2,Value:B}{Key:3,Value:D}]
/* You can only add the key, the value is defaulted */
FStringMapFString.Add(TEXT("4"));
PRINTM(FStringMapFString);//[{Key:1,Value:A}{Key:2,Value:B}{Key:3,Value:D}{Key:4,Value:}]
/* Emplace() is the same as TArray's Emplace(),
* which can avoid creating temporary objects
* when add elements.
* Pass the key and value directly to their
* respective constructors
*/
FStringMapFString.Emplace(TEXT("5"),TEXT("F"));
PRINTM(FStringMapFString);//[{Key:1,Value:A}{Key:2,Value:B}{Key:3,Value:D}{Key:4,Value:}{Key:5,Value:F}]
/* Add elements from other TMap containers
* The adding process is consistent with the
* behavior of Add()
*/
TMap<FString,FString>FStringMapFStringOther;
FStringMapFStringOther.Add(TEXT("5"),TEXT("G"));
FStringMapFString.Append(FStringMapFStringOther);
PRINTM(FStringMapFString);//[{Key:1,Value:A}{Key:2,Value:B}{Key:3,Value:D}{Key:4,Value:}{Key:5,Value: G}]
PRINTM(FStringMapFStringOther);//[{Key:5,Value:G}]
/* Support move semantics, move the original
* mapping to the existing mapping, and the clear
* the original mapping
*/
FStringMapFString=MoveTemp(FStringMapFStringOther);
2. 迭代
//C++ Setting range
for (auto i:FStringMapFString) {
//PRINT(i.Key+","+i.Value);
}
/* Create Iterator
* Iterators are divided into four types
* readable and writable iterator for key-value
* read-only and no write iterator for key-value
* readable and writable iterator for key
* read-only and no write iterator for key
*/
FStringMapFString.Empty();
FStringMapFString.Add(TEXT("1"),TEXT("A"));
FStringMapFString.Add(TEXT("2"),TEXT("B"));
for (auto i=FStringMapFString.CreateConstIterator();i;++i) {
PRINT(i.Key()+","+i.Value()+" ");
//i->Key=TEXT("1");//error
}
/* Modified content will not be synchronized to the
* currently used iterator, It can be said that
* next time it will take effect
*/
for (auto i=FStringMapFString.CreateIterator();i;++i) {
PRINT(i.Key()+","+i.Value()+" ");
i->Key=TEXT("2");
}
/* The parameter is complex, it's not
* recommended to use
*/
//for(auto i=FStringMapFString.CreateConstKeyIterator();i;++i);
//for(auto i=FStringMapFString.CreateKeyIterator();i;++i);
/* GenerateKeyArray(),GenerateValueArray()
* can generate arrays contains keys and values.
* but the origin arrays will be clear and refilled
*/
TArray<FString>StudentKeys;
TArray<FString>StudentValues;
FStringMapFString.GenerateKeyArray(StudentKeys);
FStringMapFString.GenerateValueArray(StudentValues);
PRINT(StudentKeys[0]);//2
PRINT(StudentValues[0]);//A
3. 属性
//Number of elements
PRINT(FString::FromInt(FStringMapFString.Num()));
4. 查询
/* Contains() Return whether the collection
* contains a specific value
*/
bool bResult=FStringMapFString.Contains(TEXT("1"));
/* You can use operator[] to find the value
* corresponding to the specific key.
* If it does not exist, it will assert an error
*/
//FString Oppo=FStringMapFString[TEXT("1")];
/* Find() combines the above two to return
* a pointer(nullptr) to find the corresponding
* value of the specific key
*/
FString *TempStringPointer=FStringMapFString.Find(TEXT("1"));
/* In addition, similar to the Add() function of TArray,
* there are a series of auxiliary functions
*/
/* FindOrAdd() Can't find a key-value pair that
* directly adds a specific key-defaultValue element
*/
FString TempString=FStringMapFString.FindOrAdd(TEXT("1"));
/* FindRef() Return a copy of the specific value
* corresponding to the specific key
*/
TempString=FStringMapFString.FindRef(TEXT("1"));
/* FindKey() Reverse search, find a specific key
* based on a specific value, return the first key
*/
const FString* TempStringConstPointer=FStringMapFString.FindKey(TEXT("1"));
/* FindChecked() Find the key and return the value
* if not, assert an error
*/
FStringMapFString.FindChecked(TEXT("1"));
/* FindAndRemoveChecked() Find the key and return
* the value, and remove the key-value pair, if it
* does not exist, assert an error
*/
FStringMapFString.FindAndRemoveChecked(TEXT("1"));
/* FindByHash() Search by the hash value of the key */
//FStringMapFString.FindByHash();
/* FindOrAddByHash() Search according to the hash
* value of the key, if it does not exist, add it
*/
//FStringMapFString.FindOrAddByHash();
5. 移除
/* Remove() Remove specific key-value pairs
* and return the number of elements removed
* Why?
* Because we can directly manipulate data through
* iterators, there may be duplicate keys
*/
FStringMapFString.Remove(TEXT("1"));
/* RemoveAndCopyValue() Remove a specific key-value
* pair and saves the value to the incoming parameter.
* There exists key-value pair ? true : false
*/
FStringMapFString.RemoveAndCopyValue(TEXT("1"),TempString);
/* FindAndRemoveChecked() Find the key and return the value
* and remove the key-value pair, assert an error
*/
//FStringMapFString.FindAndRemoveChecked();
/* Empty(),Reset() can clear the mapping
* The difference is that Empty() can specify
* reserved allocated memory, Reset cannot specify
*/
FStringMapFString.Empty(12);
FStringMapFString.Reset();
6. 排序
TMap<FString,FString>FStringMapFStringSort;
FStringMapFStringSort.Emplace(TEXT("3"),TEXT("3"));
FStringMapFStringSort.Emplace(TEXT("1"),TEXT("1"));
FStringMapFStringSort.Emplace(TEXT("2"),TEXT("2"));
/* Sort is combination of multiple sorting,
* quick sorting, heap sorting, bubble sorting, etc
*/
FStringMapFStringSort.KeySort([](const FString&a,const FString&b) {
return a.Compare(b)==1?true:false;//Descending
});
PRINTM(FStringMapFStringSort);//[{Key:3,Value:3}{Key:2,Value:2}{Key:1,Value:1}]
FStringMapFStringSort.ValueSort([](const FString&a,const FString&b){
return a.Compare(b)==1?true:false;//Descending
});
PRINTM(FStringMapFStringSort);//[{Key:3,Value:3}{Key:2,Value:2}{Key:1,Value:1}]
/* There is also a stable version of key-value
* sorting, merge sort implementation
*/
//FStringMapFStringSort.KeyStableSort([](){});
//FStringMapFStringSort.ValueStableSort([](){});
7. 内存
TMap<FString,FString>FStringMapFStringSlack;
//Reserve Pre-allocation mapping
FStringMapFStringSlack.Reserve(10);
/* Shrink() Remove unused memory, because
* it is removed from the end of the container,
* unused memory at the beginning or in the middle
* will not be removed
*/
FStringMapFStringSlack.Shrink();
/* Compact() Can move all unused memory
* to the end of the container, can combined
* with Shrink()
*/
FStringMapFString.Compact();
/* CountBytes(),GetAllocatedSize()
* is used to analyze memory usage
*/
//FStringMapFStringSlack.CountBytes();
PRINT(FString::FromInt(FStringMapFStringSlack.GetAllocatedSize()));
8. 类键
//TMap use class/struct as key
struct FStruct_Rand {
FString Guid;
FString A;
FString B;
FStruct_Rand() {
Guid=FGuid::NewGuid().ToString();
}
};
/**
* @brief interface
* @tparam ValueType value type.
* @param KeyInitType key type.
* @param FString the type of Tpair key,same as KeyInitType.
* @param ElementInitType element type.
* @function GetSetKey Returns the element's key.
* @function Matches Returns true if A and B are equal, false otherwise.
* @function GetKeyHash returns the hash of key.
*/
template<typename ValueType>
struct TStruct_MapKeyFuncs: BaseKeyFuncs<TPair<FStruct_Rand,ValueType>,FString> {
private:
typedef BaseKeyFuncs<TPair<FStruct_Rand,ValueType>,FString>Super;
public:
typedef typename Super::ElementInitType ElementInitType;
typedef typename Super::KeyInitType KeyInitType;
static KeyInitType GetSetKey(ElementInitType Element) {
return Element.Key.Guid;
}
static bool Matches(KeyInitType A,KeyInitType B) {
return A.Compare(B,ESearchCase::CaseSensitive)==0;
}
static uint32 GetKeyHash(KeyInitType Key) {
return FCrc::StrCrc32(*Key);
}
};
// can then be used as a normal key
TMap<FStruct_Rand,FString,FDefaultSetAllocator,TStruct_MapKeyFuncs<FString>>CustomMap;
9. 其他自行练习
四. 其他
宏定义真的很好用
#define PRINT(String) {if (GEngine){GEngine->AddOnScreenDebugMessage(-1,10.0f,FColor::Red,*(String));}}
#define PRINTA(IntArray) {\
FString ArrayMessage=TEXT("[");\
for (auto i=IntArray.begin();i!=IntArray.end();++i){\
ArrayMessage+=FString::FromInt(*i)+",";\
}\
ArrayMessage.RemoveAt(ArrayMessage.Len()-1);\
PRINT(ArrayMessage+"]");\
}
#define PRINTM(FStringMapFString) {\
FString MapMessage = TEXT("[");\
for (auto i = FStringMapFString.begin(); i != FStringMapFString.end(); ++i) {\
MapMessage +=" {Key: "+i->Key + ",";\
MapMessage +="Value: "+i->Value + "} ";\
}\
PRINT(MapMessage+"]");\
}