Reputation: 388
I'm trying to recursively get all the values (and keys) of a std::map<string, int>
in C++.
By aMap.begin()->first
, I get the key of the first element.
By aMap.begin()->second
, I get the value of the first element.
Is there a way to get a map that excludes the first value (already used) in the map? The aMap.erase(aMap.begin())
is giving me the error: (rest of map)
Invalid arguments '
Candidates are:
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> mapToCode(std::map<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int,std::less<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>,std::allocator<std::pair<const std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int>>>)
'
Am I not understanding some basic functionalities of C++ standard map?
Here is the function I'm working with:
using std::map;
string mapToCode(map<string, int> aMap) {
string returnString = "Dict(";
if (aMap.empty()) {
return returnString + ")";
} else {
string hold = mapToCode(aMap.erase(aMap.begin())) + "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")";
return returnString + hold;
}
}
This is the class that's using it:
Dictionary::Dictionary() {
}
Dictionary::Dictionary(Dictionary dicObject, string key, int value) {
std::map<string, int> newDict;
newDict[key] = value;
newDict.insert(dict.begin(), dict.end());
dict = newDict;
}
string Dictionary::toCode() {
if (empty()) {
return "Dictionary()";
} else {
return mapToCode(dict);
}
}
Upvotes: 0
Views: 280
Reputation: 331
I am not actually sure what you are trying to achieve so I don't know the order to traverse the map :P But I guess this is somewhat close to what you want:
std::string mapToCode(const std::map<std::string, int>& map, std::map<string, int>::iterator it)
{
std::string returnString = "Dict(";
if (it == std::end(map))
{
// Not sure if you really wanted to return returnString + ")";
return ""; // returnString;
}
std::string hold = mapToCode(map, std::next(it)) + "\"" + it->first + "\", " + std::to_string(it->second) + ")";
return returnString + hold;
}
Tested this on this input:
int main()
{
std::map<std::string, int> map;
map.insert(std::make_pair("a", 1));
map.insert(std::make_pair("b", 2));
std::cout << mapToCode(map, map.begin()) << std::endl;
return 0;
}
Output is:
Dict(Dict("b", 2)"a", 1)
Notes: Instead of erasing, which might be expensive, we can use the standard library's std::next to move the iterator to the next place in the container :)
Prefer using std before each call to the standard library and avoid using namespace std.
Notice the const& instead of passing the map by value. It prevents copying the entire map.
For the second part regarding copy constructors:
Dictionary::Dictionary(const Dictionary& other)
{
// I am assuming that dict is the class variable that you use to store the actual map in the class
// Also this "appends" to the existing dictionary
// If you want to first delete the old one's data, clear the dict
// dict.clear()
dict.insert(other.begin(), other.end());
}
Upvotes: 1
Reputation: 596417
This line:
string hold = mapToCode(aMap.erase(aMap.begin())) + "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")";
doesn't work, because the output of erase()
is not the modified map
, like you are expecting. And even if it did, you would be accessing aMap.begin()
after aMap.erase()
modified aMap
, which will fail after the last element has been erased. You would need something more like this instead:
string hold = "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")";
aMap.erase(aMap.begin());
hold = mapToCode(tmp) + hold;
But, why are you using recursion at all? An iterative loop would suffice instead:
string mapToCode(const map<string, int> &aMap) {
string returnString = "Dict(";
if (!aMap.empty()) {
auto toStr = [](const std::pair<const string, int> &aElement) {
return "[\"" + aElement.first + "\", " + std::to_string(aElement.second) + "]";
};
auto iter = aMap.begin();
returnString += toStr(*iter);
while (++iter != aMap.end()) {
returnString += "," + toStr(*iter);
}
}
return returnString + ")";
}
Upvotes: 0