map<string>, vector<string>> myMap

Pages: 12
Sep 4, 2015 at 7:58am
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.
Sep 4, 2015 at 8:59am
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
Sep 4, 2015 at 9:18am
Soa i have to use the multi_map?

Thank you for the info.

Wiall try asap.

Sep 4, 2015 at 11:49am
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.

Sep 4, 2015 at 3:04pm
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.
Sep 4, 2015 at 4:30pm
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
Sep 8, 2015 at 7:42am
@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?
Sep 8, 2015 at 8:13am
Sep 8, 2015 at 9:53am
It's c++14 related? I have to modify the functions above, cause i use c++11 max.
Sep 8, 2015 at 11:20am
You can remove quoted and either add quotes manually or go without them. It is not strictly nessesary here.
Sep 8, 2015 at 3:22pm
> 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.
Sep 8, 2015 at 3:54pm
Thank you for you patience and thank you for the examples.



Sep 9, 2015 at 8:59am
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 Sep 9, 2015 at 10:34am
Sep 9, 2015 at 1:52pm
> 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
Sep 10, 2015 at 7:59am
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.


Sep 10, 2015 at 1:54pm
> 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?
Sep 10, 2015 at 4:17pm
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.
Sep 10, 2015 at 4:38pm
In that case, isn't the key to your map really a pair of strings?
Sep 10, 2015 at 5:39pm
Yes

thank you all for the explanation.

@dhayden

The number of string can vary everytime
Sep 11, 2015 at 1:30am
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