Let's say I have a string
std::string test = "test test";
I can replace the letter e in that string by another letter using the replace
function
std::replace(test.begin(), test.end(), 'e', 'E');
How can I do the same but with a map<String, Vector<string>>
?
For example
std::map<std::string, std::vector<std::string>> myMap;
myMap["test"] = {"test1,test2,test3"};
myMap["test2"] = {"test21", "test22"};
I want to change all the e by E in this map
CodePudding user response:
You already know how to perform your replacement operation over a std::string
. Nothing prevents you from doing the same over a container (on the basis that the container contains strings, which is the case here).
So, for std::map<std::string, std::vector<std::string>>
, you just have to iterate over the map, then over the vectors, and then replace the values the way you want.
But, since you want to perform the replacement not only for the values of the map but also for the keys, it becomes trickier.
As you already know, you can't modify keys in a map. So you have two solutions left, you may either:
- Create new elements {key, value} into the map and remove the old ones afterwards
- Create a new map and overwrite the original one
I think the second solution is the easiest to implement.
Possible implementation:
What we want is a function that takes a reference to the map and operates the replacements for it.
For the implementation, I decided to go for the second of the above solutions (overwrite the map with the newly created one).
The strategy I have chosen here is:
- To break down the process into several functions and hide the machinery inside a wrapping class.
- As we don't need an instance of this class to run the process, we'll mark the functions as
static
. - Only the desired function (meant to be used by the user) will be
public
and thus accessible/callable outside of the class.
That would give us:
using MyMap = std::map<std::string, std::vector<std::string>>; // For readability purposes
class e2E
{
private:
// Get a replaced version of the given string
static std::string e2E_str(const std::string & s);
// Get a replaced version of the given map
static MyMap e2E_MyMap(const MyMap & m);
public:
// Compute the replacements over the map
static void compute(MyMap & m);
};
The e2E_str()
function is just an implementation of the replacement for a std::string
.
The e2E_MyMap()
function is the implementation of the process that generates a new map.
The compute()
function is just the implementation of the overwriting (straightforward by design).
We then obtain:
std::string e2E::e2E_str(const std::string & s)
{
std::string r(s);
std::replace(r.begin(), r.end(), 'e', 'E');
return r;
}
MyMap e2E::e2E_MyMap(const MyMap & m)
{
MyMap result;
std::string key;
for(const auto & [k, v] : m)
{
key = e2E_str(k);
result[key] = {};
for(const std::string & s : v)
result[key].push_back(e2E_str(s));
}
return result;
}
void e2E::compute(MyMap & m)
{
m = e2E_MyMap(m);
}
Test:
For readability purposes, we can define a display()
function to display the map.
It may look like:
void display(const MyMap & m, std::ostream & os)
{
for(const auto & [k, v] : m)
{
os << k << ":\n";
for(const std::string & s : v)
os << " " << s << '\n';
}
os << std::endl;
}
And we can then call our replacement function as follows:
int main()
{
// Create the map
MyMap my_map {{"test1", {"There", "That", "Word", "The"}}, {"test2", {"This", "Where"}}};
// Display the map contents before the replacement operation
display(my_map, std::cout);
// Perform the replacements
e2E::compute(my_map);
// Display the map contents after the replacement operation
display(my_map, std::cout);
return 0;
}
If you want to quickly execute and check the results of this test click here.
CodePudding user response:
For a pre C 17 solution, I recommend creating a new map
, like @Fareanor has shown.
If you can use C 17 or later there is however another option that doesn't require a second map but involves extracting each data carrying node out of the map, modifying it (including the Key) and then inserting the node back into the map.
The same restriction regarding modifying the Key while it's still in the map stands, so, loop over the Key/Value pairs in the map, rip out one node at a time, change it - and put it back into the map.
A pseudo version:
for(it = myMap.begin(); it != myMap.end(); <no increment> ) {
next = it 1; // save the iterator to next element because ...
mapnode = myMap.extract(it); // ... `extract` invalidates `it`
// modify the Key
cap_e(mapnode.key()); // cap_e() capitalizes 'e' in a string
// modify the mapped Value
for every str in mapnode.mapped():
cap_e(str)
// re-insert the modified node
myMap.insert(move(mapnode));
it = next; // set the iterator `it` to what was saved at the top
}