is it possible to access the last element of a TMap container without iterating from the beginning? A reverse iterator or an iterator after last element such as .end() in c++ so I can decrement it and access the last element.
The documentation does not mention anything about .begin() or .end() but I see it available as functions for TMapBase<> with some warnings to not use it directly or that .end() returning the endpoint of the ray (which I have no idea what that has to do with a containerā¦).
There is no such thing as last element in the Map. This is not how maps work. Extract keys (using Keys node) ,and get last element from the array. But Last element there will not necessarry be the last one added.
But isnāt the map sorted by keys though? Anyway, maybe I should have been clearer. I donāt mean the last āinsertedā element, I just mean the last element when you iterate through this container.
Keys are āsortedā as they are added. And it really depends on what keys are you using. You should provide some use case (exactly what would you like to do) so that we might be able to help you a bit
So I am iterating through a map with an iterator and at some point inside the cycle I am checking if the actual key of the element is the last one and according to that I return a value.
I am incrementally creating a combination of a 2D array (here AVar) and the combination (indices to the array) is stored in CurrentCombination
bool NextCombination(UPARAM(ref) TMap<FString, int32> & CurrentCombination){
//deal with error cases here
for(const TPair<FString, FSTArray> & pair: AVar){
int32 maxNum = pair.Value.Array.Num();
if(CurrentCombination[pair.Key] + 1 < maxNum){
CurrentCombination[pair.Key]++; //increase by one and return
return true;
}
else{
if(pair.Key == lastKeyInMap){ //the combination was the last one
return false;
}
else{
CurrentCombination[pair.Key] = 0; //reset and increase the next one
continue;
}
}
}
UE_LOG(LogTemp, Warning, TEXT("Something went wrong while getting the next combination.")); //ideally this piece of code is never reached
return false; //otherwise the compiler won't work
}
I guess I can just iterate through the keys and remember the last one, before iterating again. I just wondered if I can get the lastKeyInMap with just one line of code.
As Bojann said there is no such thing as a ālastā element. The items in a map arenāt even āsortedā in the traditional sense of the word. The problem that you will run into with your implementation is that inserting a new element could cause any of the following things to happen: a) the existing element you thought was last to remain so, b) the new element becomes ālastā or c) the container reorders and some other element of the map becomes the last. Iām not even 100% sure that two iterations of a map when there havenāt been changes to it will result in the same iteration, it seems like it should but I donāt know if itās guaranteed.
If order matters for what you are trying to do with the operation, you should really choose a different container. Or work with multiple containers so that you have one that preserves order (call it A) and another that maps that FString key into A somehow (by index or something).
I thought since the keys are sorted (and I know that at least std::map is sorted associative container) the iterator will always go through the elements in the same order as long as the map is not modified. I would not rely on this if it was a hashmap.
On your suggestion I have made a copy of the keys to an array and iterate through the array instead, the code looks neater as well.
To quote Adam Savage: āWell thereās your problem!ā. TMaps are hashed associative containers, not sorted ones. In order to be a key in a TMap (or be included in a TSet) the type has to have a overload of the GetTypedHash function.
You can sort a TMap using the KeySort() function, then iterate over the elements in order. Thereās no āLastā accessor, but you can generate an array of keys which will retain that order. Sorting remains in place until the Map is modified again.
To be honest though if order is important, a TMap is probably the wrong container to start with.
At some point I am not modifying the map anymore and I am just reading from it. Since you can iterate over keys/elements with an iterator in a map, I wanted instant access to the last element, the 1 element before the iterator points to the .end().
I do not care what order the elements are sorted in a map during the modification, but when I iterate over map afterwards, I expected same iteration order every time until I discard/modify/recreate the map - then the iteration order might change again and it would not be a problem in this case. However, the TMap<> in UE is a hashmap, so apparently I cannot depend on the same iteration order even if I had NOT modified the map.
I will leave the question open for a bit longer in case someone want to contribute something, but right now my solution was to just dump the keys into an array and iterate this array.
Yep. While itās unlikely that it will change if you make no changes to it at all, youāre not ever guaranteed to get the same iteration order. So, ālastā is not really defined here. Of course, the keys are also not guaranteed to be in the same order between requests, either, unless you sort them, or retain the same array of keys between iterations.
If you must have a stable order, you should use a different data structure. If all you need to know is āiām at the endā you should be able to check if Next is null, or keep track of how many youvāe accessed and compare it to the length, or whatever.
If youāre routinely iterating the TMap, rather than accessing it via individual keys, then you may have chosen the wrong structure to begin with. If you need both key access, and frequent iterations, you might implement something like a TArray of USTRUCT, where the struct contains your key and your data, then you can use the stable order of the TArray for iteration, as well as implement a way to search it via your own Key field.
There might be an already provided structure that does something like that, or features in TArray for adding that, itās not something Iāve explored too much of.
The solution is to use TSortedMap. However, in Epicās infinite wisdom, they added a sorted container, but did not provide easy accessors to get the first and last elements.
So youāll have to do something like this:
using FYourSortedMap = TSortedMap<int32, FString>;
FYourSortedMap SortedMap;
FYourSortedMap::TConstReverseIterator It(SortedMap);
if (It)
{
FString LastValueInMap = It.Value();
ā¦
}