HelloWorld
HelloWorld

Reputation: 388

map<string, int> get rest of map (C++)

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

Answers (2)

AmN
AmN

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

Remy Lebeau
Remy Lebeau

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

Related Questions