ava
ava

Reputation: 378

Efficient way to get key from value when map contain vector of string as value

How to get key using value which is vector of string and vice versa. Below is my code.

#include<iostream>
#include<map>
#include<string>
#include <unordered_map>
#include <vector>

using namespace std;
int main()
{
std::unordered_map<std::string, std::vector<std::string>> Mymap;
Mymap["unique1"] = {"hello", "world"};
Mymap["unique2"] = {"goodbye", "goodmorning", "world"};
Mymap["unique3"] = {"sun", "mon", "tue"};

for(auto && pair : Mymap) {
        for(auto && value : pair.second) {
                std::cout << pair.first<<" " << value<<"\n";
                if(value == "goodmorning") // how get key i.e unique2 ?
        }}
}

case 1: When value is input. key is output.

Input  : goodmorning
output : unique2

case 2: When key is input value is output.

Input : unique3
output: sun ,mon ,tue

Note : No boost library available.

Upvotes: 3

Views: 228

Answers (3)

Donotalo
Donotalo

Reputation: 13025

For case 1, a combination of find_if and any_of will do the job.

For case 2, you can simply use the find method of unordered_map.

#include<iostream>
#include<map>
#include<string>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    unordered_map<string, vector<string>> Mymap;
    Mymap["unique1"] = { "hello", "world" };
    Mymap["unique2"] = { "goodbye", "goodmorning", "world" };
    Mymap["unique3"] = { "sun", "mon", "tue" };

    // Case 1

    string test_value = "goodmorning";
    auto iter1 = find_if(Mymap.begin(), Mymap.end(),
        [&test_value](const decltype(*Mymap.begin()) &pair)
        {
            return any_of(pair.second.begin(), pair.second.end(), [&test_value](const string& str) { return str == test_value; });
        });

    if (iter1 != Mymap.end())
    {
        cout << "Key: " << iter1->first << endl;
    }
    else
    {
        cout << "No key found for " << test_value;
    }

    // Case 2

    test_value = "unique3";
    auto iter2 = Mymap.find(test_value);
    if (iter2 != Mymap.end())
    {
        int first = true;
        for (auto v : iter2->second)
        {
            cout << (first ? "" : ", ") << v;
            first = false;
        }
        cout << endl;
    }
    else
    {
        cout << "No value found for key " << test_value << endl;
    }

    return 0;
}

Upvotes: 3

Gem Taylor
Gem Taylor

Reputation: 5613

Create another map going the other way for every vector entry?

If the array entries are not unique, then you would need to do the same map-to-vector, or use multimap.

Also consider using hash map (unordered_map), and stringview as ways to reduce the memory usage of the second map?

But the best answer would be the boost 2-way map, sorry. You could wrap the two maps in your own class that exposes the functionality of a 2-way map.

Upvotes: 0

NiVeR
NiVeR

Reputation: 9786

The key is stored in pair.first. Just use that if your use-case is in loop iteration as you illustrated.

If you mean in any use, without iteration, that is, given a value obtain the associated key, there is not a direct way to do that. You could build inverse maps for each value to key but that would not be really efficient considering also the fact that you would also need unique values.

Upvotes: 2

Related Questions