javaNoob
javaNoob

Reputation: 23

Finding a way to push_back matched key and values from a map into vector

I had code that was similar to this in Java, but getting it to work in C++ is a different story. Currently, this function does find the key correctly and pushes the key to the back of my vector. I would like to grab both the key and its pair of values to all be inserted into the same index of the vector. I have looked into using a pair for my vector so it would be (key, pair of values), which I am not sure I am able to do.

vector<string> getIfPresentPartOfSpeech(multimap<string, pair<string, string>> dictionary, string name) {
    vector<string> response;
    auto it = dictionary.begin();
    while (it != dictionary.end()) {
        // Check if value of this entry matches with given value
        if (it->second.first == name) {
            // Yes found
            // Push the key in given map
            response.push_back(it->first);
        }
        // Go to next entry in map
        it++;
    }
    return response;
}

Upvotes: 0

Views: 463

Answers (2)

tnt
tnt

Reputation: 1184

You can use std::copy_if in <algorithm> without having to write an explicit loop manually. Also pass dictionary by (constant) reference to avoid unnecessary copy:

#include <algorithm>
#include <map>
#include <utility>
#include <vector>

// You'll need C++14 to use `auto const& kv` in your lambda expression
std::vector<std::pair<const std::string, std::pair<std::string, std::string>>>
getIfPresentPartOfSpeech(
    const std::multimap<std::string, std::pair<std::string, std::string>>&
        dictionary,
    const std::string& name)
{
    std::vector<
        std::pair<const std::string, std::pair<std::string, std::string>>>
        res;
    std::copy_if(begin(dictionary), end(dictionary), std::back_inserter(res),
                 [&](auto const& kv) { return kv.second.first == name; });
    return res;
}

//test
int main()
{
    std::multimap<std::string, std::pair<std::string, std::string>> dictionary{
        {"first", {"abc", "def"}},
        {"second", {"123", "456"}},
        {"first", {"asdf", "fdas"}},
        {"thrid", {"abc", "123"}},
    };
    auto res = getIfPresentPartOfSpeech(dictionary, "abc");
    for (auto& x : res)
        std::cout << x.first << " " << x.second.first << " " << x.second.second
                  << "\n";
}

Using a struct like @aep suggested would be much clearer. You'll need an extra conversion constructor for it to work with std::copy_if:

struct Response {
    std::string key;
    std::pair<std::string, std::string> value;
    // Provide a conversion constructor that convert your `dictionary` multimap
    // key-value pair into a Response object
    Response(const std::pair<const std::string,
                             std::pair<std::string, std::string>>& kv)
    : key{kv.first}, value{kv.second}
    {}
};

std::vector<Response> getIfPresentPartOfSpeech(
    const std::multimap<std::string, std::pair<std::string, std::string>>&
        dictionary,
    const std::string& name)
{
    std::vector<Response> res;
    std::copy_if(begin(dictionary), end(dictionary), std::back_inserter(res),
                 [&](auto const& kv) { return kv.second.first == name; });
    return res;
}

Upvotes: 1

aep
aep

Reputation: 1675

Define a struct for your response and return a std::vector of that type.

struct Response {
  std::string key;
  std::pair<std::string, std::string> resp_pair;
};

vector<Response> getIfPresentPartOfSpeech(multimap<string, pair<string, string>> dictionary, string name) {
    vector<Response> response;
    auto it = dictionary.begin();
    while (it != dictionary.end()) {
        // Check if value of this entry matches with given value
        if (it->second.first == name) {
            // Yes found
            // Create a Response object
            Response resp;
            resp.key = it->first;
            resp.resp_pair = it->second;
            // Push it in the vector
            response.push_back(resp);
        }
        // Go to next entry in map
        it++;
    }
    return response;
}

It's further possible optimize this by using emplace_back instead of push_back to avoid multiple copies of the container element passing around.

Upvotes: 2

Related Questions