You just do (for map
and unordered_map
)
mydict[key]=value;
Question
I currently have lots of code which looks like this:
std::unordered_map<int,int> my_dict;
.
.
.
// If the key does exist in the dictionary
if(my_dict.count(key) == 1){
my_dict[key] = value;
}
// If its a new key
else{
my_dict.insert(std::make_pair(key,value));
}
Is there any way I can speed this up by just overwriting the value every time?
Solution
You just do (for map
and unordered_map
)
mydict[key]=value;
OTHER TIPS
I think it might be fastest like this:
auto it = my_dict.find(key);
if( it != my_dict.end() ) {
it->second = value;
}
else {
my_dict.insert(std::make_pair(key,value));
}
that way you don't modify the structure of the unordered_map
if the key
already exists and you only have one lookup.
Another option in case you don't need/access value
afterwards:
my_dict[key] = std::move(value);
This might be better in cases when the assignment of value
is expensive and benefits from move-semantics.
To update for C++17, you can use:
std::unordered_map::insert_or_assign()
http://en.cppreference.com/w/cpp/container/unordered_map/insert_or_assign
All of your map functions perform a search, so you always search the map twice regardless of the key being present or not. You can leverage the fact that insert
retrieves whether the insertion took place (key did not exist) or not (key exists) and act accordingly:
std::unordered_map<int,int> mydict;
bool inserted = false;
auto position = mydict.end();
std::tie(position, inserted) = mydict.insert({key, value});
if (inserted) {
pos->second = value;
}
This would be equivalent to mydict[key] = value
, because we are assigning the new value no matter what. For types where default construction is cheap I would go with operator[]
instead, if that's the only thing you need to do with the map.
All insert
, emplace
and operator[]
can perform an additional construction of value_type
in different situations: insert
and emplace
do this before the insertion takes place and operator[]
default constructs the mapped value when key is not present. Thus, they are not ideal for types whose construction/copy/move is expensive (std::thread
, very large std::array
...). In this case, it is more appropriate to use try_emplace
instead (C++17):
std::unordered_map<int, expensive_type> mydict;
bool inserted = false;
auto position = mydict.end();
std::tie(position, inserted) = mydict.try_emplace(key, expensive_constructor_args);
if (!inserted) {
// no expensive_type has been constructed
// pos->second references the existing value
}
Usually you avoid extra typing by means of defining a function that saves you from typing the same again.
If you don't have access to C++17's insert_or_assign()
, you can implement something like this yourself:
bool InsertOrAssign(std::unordered_map& m, int key, int value) {
// Your code or one of the suggested answers goes here
}