map<string>, vector<string>> myMap

Pages: 12
Hello,

trying to figure out if could be possible to have a map in that way:


myMap ["PLUTO"] = {"DOG", "10", "Male"};
myMap ["PLUTO"] = {"PLANET" , "2,", "Solar System"};

can i later query for all the pluto in myMap?

Thank you very much.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>

// http://en.cppreference.com/w/cpp/container/multimap
using multi_map = std::multimap< std::string, std::vector<std::string> > ;

void query( const multi_map& mmap, const std::string& key )
{
    std::cout << "query key: " << std::quoted(key) << "\n\n" ;

    // http://en.cppreference.com/w/cpp/container/multimap/equal_range
    const auto pair = mmap.equal_range(key) ;

    if( pair.first == mmap.end() ) std::cout << "        *** not found ***\n" ;

    else for( auto iter = pair.first ; iter != pair.second ; ++iter )
    {
        std::cout << "        [ " ;
        for( const auto& str : iter->second ) std::cout << std::quoted(str) << ' ' ;
        std::cout << "]\n" ;
    }
    std::cout << "\n--------------\n\n" ;
}

int main()
{
    multi_map mmap =
    {
        {  "pluto", { "dog", "10", "male" } },
        {  "pluto", { "planet", "2", "solar system" } },
        {  "apple", { "fruit", "delicious" } },
        {  "apple", { "business", "inc.", "cupertino", "california" } },
        {  "apple", { "computer", "macbook", "OS X", "BSD" } },
    };

    // http://en.cppreference.com/w/cpp/container/multimap/insert
    mmap.insert( multi_map::value_type{ "apple", { "tree", "deciduous", "rosa" } } ) ;

    query( mmap, "pluto" ) ;
    query( mmap, "apple" ) ;
    query( mmap, "violin" ) ;
}

query key: "pluto"

        [ "dog" "10" "male" ]
        [ "planet" "2" "solar system" ]

--------------

query key: "apple"

        [ "fruit" "delicious" ]
        [ "business" "inc." "cupertino" "california" ]
        [ "computer" "macbook" "OS X" "BSD" ]
        [ "tree" "deciduous" "rosa" ]

--------------

query key: "violin"

        *** not found ***

--------------

http://coliru.stacked-crooked.com/a/c65a49723e22f3b5
Soa i have to use the multi_map?

Thank you for the info.

Wiall try asap.

1
2
3
4
5
6
myMap["PLUTO"].push_back("DOG");
myMap["PLUTO"].push_back("10");
myMap["PLUTO"].push_back("Male");
myMap["PLUTO"].push_back("Planet");
myMap["PLUTO"].push_back("2");
myMap["PLUTO"].push_back("Solar System");


Are you really mapping to a vector of strings? Your post suggests that the strings always come in groups of threes. If that's the case then put the 3 things in their own class and map to them.

So i have to use the multi_map?

Yes. std::map allows only one entry for a particular key (Pluto). std::multi_map allows any number of keys with with same key value.
std::map where the mapped type is a sequence of vectors is the other option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>

// http://en.cppreference.com/w/cpp/container/multimap
using data = std::vector<std::string> ;
using map_type = std::map< std::string, std::vector<data> > ;

void print( const data& record, std::ostream& stm = std::cout )
{
    stm << "[ " ;
    for( const std::string& str : record ) stm << std::quoted(str) << ' ' ;
    stm << "]\n" ;
}

void print( const std::vector<data>& records, std::ostream& stm = std::cout )
{
    for( const auto& rec : records ) print( rec, stm ) ;
    stm << '\n' ;
}

void query( const map_type& map, const std::string& key )
{
    std::cout << "query on key: " << std::quoted(key) << "\n\n" ;

    const auto iter = map.find(key) ;
    if( iter == map.end() ) std::cout << "*** not found ***\n" ;
    else print( iter->second ) ;
}

int main()
{
    map_type map =
    {
        {  "pluto", { { "dog", "10", "male" }, { "planet", "2", "solar system" } } },
        {  "apple", { { "fruit", "delicious" }, { "business", "inc.", "cupertino", "california" },
                      { "computer", "macbook", "OS X", "BSD" } } }
    };

    map["apple"].push_back( { "tree", "deciduous", "rosa" } ) ;

    query( map, "pluto" ) ;
    query( map, "apple" ) ;
}

http://coliru.stacked-crooked.com/a/d2e07043f5a2e203
@JLBorges

Thank you. Interesting.

What's std::quoted(key), btw?

the compiler tells that 'quoted' is not member of 'std'.

Moreover,

could you explain, please, the difference beetween the two sources you've proposed?
Which is the best approach?
It's c++14 related? I have to modify the functions above, cause i use c++11 max.
You can remove quoted and either add quotes manually or go without them. It is not strictly nessesary here.
> could you explain, please, the difference beetween the two sources you've proposed?

With the multimap, we can have more than one occurrence of a particular key; with each key having a different mapped data. For instance, with multimap<string,int>, we could have three entries with the key "A":
{ "A", 23 }, { "A", 17 }, { "A", 56 }.
equal_range("A") would would give us a pair of iterators; with it we can iterate over all occurrences of key "A".

With the map, keys are unique; but to have more than one value associated with a particular key, with each key we can store the mapped data as a sequence (say a vector) of many values.
With map< string, vector<int> >, for the above example, we would get: { "A", { 23, 17, 56 } }.
In this case, we would do a look up for key "A" and then iterate over the the values in the vector to go over all the different values associated with this key.

Programmer efficiency is more important than machine efficiency; use the option which you find easier to reason about and program with.
Thank you for you patience and thank you for the examples.



One more thing:

this line:
iter->second;

how to change it to return a string?

i'm trying to put the query results in a vector<string> but if try query_results.push_back(iter->second)
i get:

error: no matching function call to 'std::vector::basic_string<char> >::push_back(const std::Vector<srd::vector<srd::basic_string<char> > >&)'
Last edited on
> i'm trying to put the query results in a vector<string>

Shouldn't the query result be std::vector< std::vector<std::string> > ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>

// http://en.cppreference.com/w/cpp/container/multimap
using data = std::vector<std::string> ;
using map_type = std::map< std::string, std::vector<data> > ;

std::vector<data> query( const map_type& map, const std::string& key )
{
    const auto iter = map.find(key) ;
    return iter != map.end() ? iter->second : std::vector<data>{} ;
}

int main()
{
    map_type map =
    {
        {  "pluto", { { "dog", "10", "male" }, { "planet", "2", "solar system" } } },
        {  "apple", { { "fruit", "delicious" }, { "business", "inc.", "cupertino", "california" },
                      { "computer", "macbook", "OS X", "BSD" } } }
    };

    map["apple"].push_back( { "tree", "deciduous", "rosa" } ) ;

    for( const auto& rec : query( map, "pluto" ) )
    {
        std::cout << "[ " ;
        for( const auto& str : rec ) std::cout << std::quoted(str) << ' ' ;
        std::cout << "]\n" ;
    }
}

http://coliru.stacked-crooked.com/a/3a740ac78fe99a8f

If we really want the result as std::vector<std::string>, the all the strings in a particular subsequence should be concatenated into a singlre big string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>

// http://en.cppreference.com/w/cpp/container/multimap
using data = std::vector<std::string> ;
using map_type = std::map< std::string, std::vector<data> > ;

std::string cat( const data& record )
{
    std::string result = "[ " ;
    for( const std::string& str : record ) result += '"' + str + "\" " ;
    result += ']' ;
    return result ;
}

std::vector<std::string> query( const map_type& map, const std::string& key )
{
    std::vector<std::string> result ;

    const auto iter = map.find(key) ;
    if( iter != map.end() ) for( const auto& rec : iter->second ) result.push_back( cat(rec) ) ;

    return result  ;
}

int main()
{
    map_type map =
    {
        {  "pluto", { { "dog", "10", "male" }, { "planet", "2", "solar system" } } },
        {  "apple", { { "fruit", "delicious" }, { "business", "inc.", "cupertino", "california" },
                      { "computer", "macbook", "OS X", "BSD" } } }
    };

    map["apple"].push_back( { "tree", "deciduous", "rosa" } ) ;

    for( const std::string& str : query( map, "pluto" ) ) std::cout << str << '\n' ;
}

http://coliru.stacked-crooked.com/a/1bbbe82d4770e061
Thank you for the reply.

All these examples are really good to learn.

Btw, why for the previous code i get error: no matching function call to 'std::vector::basic_string<char> >::push_back(const std::Vector<srd::vector<srd::basic_string<char> > >&)' ?


Moreover, it's possible to have a version of the routine as follow:

vector<string> my_query_result=query("Pluto");

Maybe there are limitation using the iterator and for (const auto...?

My intention was to iterate over the multi_map and push the result into a vector of string, but as you can see i get the error mentioned above.


> Moreover, it's possible to have a version of the routine as follow:
> vector<string> my_query_result=query("Pluto");

If the multimap contains two occurrences of the key "Pluto"
{ "pluto", { "dog", "10", "male", "fawn" } }
{ "pluto", { "planet", "2", "solar system" } }


what should the query result std::vector<std::string> contain?
You're right.

If i query for "pluto" i must have the possibilty to choose the first, second or other occurrences of the key. So i should be able to selectively return the right row. Maybe the first string of the key could be considered as another key value.

SQL comes to my mind since we are talking about "query". Select first where key="pluto" and first value ="dog". But we are jumping in the database world.
In that case, isn't the key to your map really a pair of strings?
Yes

thank you all for the explanation.

@dhayden

The number of string can vary everytime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>
#include <algorithm>

using multi_map = std::multimap< std::string, std::vector<std::string> > ;

bool contains( const std::vector<std::string>& values, const std::string& attribute )
{ return std::find( std::begin(values), std::end(values), attribute ) != std::end(values) ; }

std::vector<std::string> query( const multi_map& mmap, const std::string& key, const std::string& attribute )
{
    std::vector<std::string> result ;

    const auto pair = mmap.equal_range(key) ;

    if( pair.first != mmap.end() )
    {
        for( auto iter = pair.first ; iter != pair.second ; ++iter )
        {
            if( contains( iter->second, attribute ) )
            {
                for( const std::string& str : iter->second )
                    if( !contains( result, str ) ) result.push_back(str) ;
            }
        }
    }

    return result ;
}

void print_query_results( const multi_map& mmap, const std::string& key, const std::string& attribute )
{
    std::cout << std::quoted(key) << " + " << std::quoted(attribute) << " =>  [" ;
    for( const auto& str : query( mmap, key, attribute ) ) std::cout << std::quoted(str) << ' ' ;
    std::cout << "]\n" ;
}

int main()
{
    multi_map mmap =
    {
        {  "pluto", { "dog", "10", "male" } },
        {  "pluto", { "planet", "2", "solar system" } },
        {  "pluto", { "dwarf", "planet", "134340", "solar system" } },
        {  "apple", { "fruit", "delicious" } },
        {  "apple", { "business", "inc.", "cupertino", "california" } },
        {  "apple", { "computer", "macbook", "OS X", "BSD" } },
        {  "apple", { "tree", "deciduous", "rosa" } },
    };

    print_query_results( mmap, "pluto", "dog" ) ;
    print_query_results( mmap, "apple", "BSD" ) ;
    print_query_results( mmap, "pluto", "solar system" ) ;
}

http://coliru.stacked-crooked.com/a/6e548a7ea9b36d19
Pages: 12