This article may be helpful for those who are familiar with standard containers and would like to learn Unreal-specific ones, or for those who already have a knowledge of the containers but would like to explore them a little deeper.

Here is information about the following containers: TArray, TSet, TMap, and a basic overview of the TMultiMap and TSortedMap.

TArray

Let’s start with TArray. TArray is a dynamically sized array, similar to std::vector in the standard library.

The primary use of TArray is to provide an easy way to iterate over its elements using both traditional and range-based for loops, with good memory and performance.

Traditional for loop example
TArray<int32> IntArray{5, 10, 15, 20, 25};

for (int32 Index = 0; Index < IntArray.Num(); ++Index)
{
    UE_LOG(LogTemp, Log, TEXT("Traditional for loop iteration. Element value: %d"), IntArray[Index]);
}

Range-based for loop example
TArray<int32> IntArray{5, 10, 15, 20, 25};

for (int32 Element : IntArray)
{
    UE_LOG(LogTemp, Log, TEXT("Range-based for loop iteration. Element value: %d"), Element);
}

From a time complexity perspective, all TArray operations except for indexing have linear O(n) time complexity.

TSet

TSet is a dynamic collection of unique elements stored as keys, similar to the std::set container in the standard library. It uses a hash table implementation to efficiently store and retrieve the elements, where the actual key is passed through a hash function to generate a numerical representation.

Technically, TSet encapsulates a TSparseArray, allowing hashed keys to be optimally stored as indexes.

As a result, this container is designed for instant (in constant time O(1)) element search.

However, the elements in this container are likely to have an inconsistent order in memory. And accessing an element using a hash function each time makes it not the preferred option for iterating over all elements.

Example of searching for an element by key, O(1)
TSet<FString> StringSet{TEXT("First element"), TEXT("Second element"), TEXT("Third element")};

// The value will be true since there is a "Second element" element
bool bFound = StringSet.Contains(TEXT("Second element"));

TMap

TMap is a dynamically sized associative array, similar to TSet, that stores elements as key-value pairs. It is implemented in a similar manner as std::unordered_map and has a structure similar to a hash table, but the main difference is that not keys are hashed, but key-value pairs.

Technically, TMap encapsulates a TSet containing a TPair<KeyType, ValueType>.

Thus, all operations, except searching for an element by value, occur in constant time O(1).

Since this container works similarly to TSet, it is not recommended to use it when iterating over all elements for the same reasons

Diving even deeper: to find the keys inside TPair<KeyType, ValueType>, TMap uses key functions called TDefaultMapHashableKeyFuncs, which handles the matching and calling the hashing function (GetKeyHash) based on the input key. Internally, it has its own implementation of KeyInitType with replacement of the element type for search from TPair<KeyType, ValueType> to KeyType, which allows you to specify only the key instead of the full pair when searching in TMap. Essentially, you can think of TMap<KeyType, ValueType> as TSet<TPair<KeyType, ValueType>, TDefaultMapHashableKeyFuncs<KeyType, ValueType, false>>, with the final “false” indicating to disallow duplicate keys, which are not allowed in TMap by design.

Example of searching for an element by key, O(1)
TMap<FString, float> StringFloatMap
{
	{TEXT("First element"), 0.1f},
	{TEXT("Second element"), 0.2f},
	{TEXT("Third element"), 0.3f}
};

// The value found will be 0.2
float FoundValue = *StringFloatMap.Find(TEXT("Second element"));

Example of searching for an element by value, O(n)
TMap<FString, float> StringFloatMap
{
	{TEXT("First element"), 0.1f},
	{TEXT("Second element"), 0.2f},
	{TEXT("Third element"), 0.3f}
};

// The key found will be "Third element"
FString FoundKey = *StringFloatMap.FindKey(0.3f);

Similar containers to TMap

TMultiMap operates similarly to TMap, but is closer to the standard std::unordered_multimap, as it allows multiple values to be assigned for each key. To some extent, you can think of TMultiMap<KeyType, ValueType> as TSet<TPair<KeyType, ValueType>, TDefaultMapHashableKeyFuncs<KeyType, ValueType, true>>, where the “true” argument in TDefaultMapHashableKeyFuncs specifies that duplicate keys are allowed.

There is an even more TMap-like container called TSortedMap, which is more efficient than TMap when the number of elements is small. It is similar to std::map in that finding has logarithmic complexity O(log n), since the algorithm uses a binary search, although it is not implemented as a red-black tree , but simply as an array of key-value pairs (TArray<TPair<KeyType, ValueType>>), so adding and removing takes linear time O(n).