Print all the occurrences of a word in a MAP




Hello everyone,



i'm trying to count how many paired words are present in a map as follow:
 
map<string, string>::iterator it = dictionary.find(wordToSearch);


I populated the dictionary this way:

1
2
dictionary.insert(make_pair("PLUTO", "MICKEY"));
dictionary.insert(make_pair("PLUTO", "DONALD"));


why with the following code i can output only the first occurrence?

1
2
3
4
5
6
7
    for (it = dictionary.begin();
            it != dictionary.end(); ++it)
    {
        if (it->first==wordToSearch) {
            cout << it->first << "\t" << it->second << endl;
        }
    }


thank you very much
Last edited on
In std:map the keys are unique: there can be only one key value pair for a particular key.
Use std::multi_map instead of std:map if multiple entries with the same key is required.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <map>
#include <string>

int main()
{
    std::multimap<std::string,std::string> mmap { { "PLUTO", "MICKEY" }, { "PLUTO", "DONALD" } } ;
    mmap.emplace( "PLUTO", "HUEY" ) ;
    // etc.

    const auto pair = mmap.equal_range( "PLUTO" ) ;
    for( auto iter = pair.first ; iter != pair.second ; ++iter )
        std::cout << iter->first << ' ' << iter->second << '\n' ;

    std::cout << '\n' ;

    // or C++ 17:
    const auto [ begin, end ] = mmap.equal_range( "PLUTO" ) ;
    for( auto iter = begin ; iter != end ; ++iter )
    {
        const auto& [ key, value ] = *iter ;
        std::cout << key << ' ' << value << '\n' ;
    }
}

http://coliru.stacked-crooked.com/a/ba180b20683db751
Thank you.

I thought this was possible.

Have to modify a little the code, sice the dicttionary rely on a map

Kind regards
Last edited on
@JLBorges

looking at the code you posted, is not possible to as follow:
1
2
std::multimap<std::string,std::string> mmap { { "PLUTO", "A DOG", "CUTE DOG", "THIS DOG BELONGS TO MICKEY" }, { "PLUTO", "DONALD" } } ;
    mmap.emplace( "PLUTO", "HUEY" ) ;
Last edited on
This is possible:

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
#include <iostream>
#include <map>
#include <string>

template < typename K, typename V, typename KK, typename VV >
void insert_all( std::multimap<K,V>& mmap, const KK& key, std::initializer_list<VV> values )
{ for( auto v : values ) mmap.emplace( key, v ) ; }

int main()
{
    std::multimap<std::string,std::string> mmap { { "PLUTO", "MICKEY" }, { "PLUTO", "DONALD" } } ;
    mmap.emplace( "PLUTO", "HUEY" ) ;
    insert_all( mmap, "PLUTO", { "A DOG", "CUTE DOG", "THIS DOG BELONGS TO MICKEY" } ) ;
    insert_all( mmap, "Neptune", { "Sylvester", "Bugs", "Daffy", "Tweety", "Wile E Coyote" } ) ;
    // etc.

    const auto pair = mmap.equal_range( "PLUTO" ) ;
    for( auto iter = pair.first ; iter != pair.second ; ++iter )
        std::cout << iter->first << ' ' << iter->second << '\n' ;

    std::cout << '\n' ;

    // or C++ 17:
    const auto [ begin, end ] = mmap.equal_range( "Neptune" ) ;
    for( auto iter = begin ; iter != end ; ++iter )
    {
        const auto& [ key, value ] = *iter ;
        std::cout << key << ' ' << value << '\n' ;
    }
}

http://coliru.stacked-crooked.com/a/7e5ad4053ea11ea5
Thank you JLB,

In that case i can have multiple keys, i.e. "PLUTO", with multiple associated strings?

Cool.

there's a limit to the number of arguments for a key?

moreover, it's possibile to access directly the second, third.... elements, as well as counting the number of elements for each key?

1
2
3
4
5
const auto pair = mmap.equal_range( "PLUTO" ) ;
    for( auto iter = pair.first ; iter != pair.second ; ++iter )
        std::cout << iter->first << ' ' << iter->second << '\n' ;

    std::cout << '\n' ;


Last edited on
> there's a limit to the number of arguments for a key?

No. (Other than the limitation of available memory.)


> possible to access directly the second, third.... elements,
> as well as counting the number of elements for each key?

Strongly consider using a map where the mapped value is a sequence of strings.
That is std::vector<std::string>. For instance:

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
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <iomanip>

template < typename T, typename U >
void push_back_all( std::vector<T>& vec, std::initializer_list<U> values )
{ vec.insert( vec.end(), values.begin(), values.end() ) ; }

int main()
{
    std::map< std::string, std::vector<std::string> > map
    {
        { "PLUTO", { "A DOG", "CUTE DOG", "THIS DOG BELONGS TO MICKEY" } },
        { "Neptune", { "Sylvester", "Bugs", "Daffy", "Tweety", "Wile E Coyote" } }
    };

    push_back_all( map["PLUTO"], { "Mickey", "Donald", "Huey" } ) ;
    push_back_all( map["Jupiter"], { "d'Artagnan", "Athos", "Porthos", "Aramis" } ) ;

    for( const std::string key : { "PLUTO", "Neptune", "Jupiter", "asdfgh" } )
    {
        std::cout << "key: " << std::quoted(key) ;

        const auto iter = map.find(key) ; 

        if( iter == map.end() ) std::cout << " is not present in the map\n" ;

        else
        {
            std::cout << "  values (" << iter->second.size() << "): [ " ;
            for( const auto& value : iter->second ) std::cout << std::quoted(value) << ' ' ;
            std::cout << "]\n\n" ;
        }
    }
}

http://coliru.stacked-crooked.com/a/d076dad2b6f6d63e
@JLB

Thank you. You rocks, dude. Lightining fast!

Strongly consider using a map where the mapped value is a sequence of strings.
That is std::vector<std::string>. For instance:


I can still use in that case more than one word with the same key?

It is possible with some trick to edit one of the string associated? Assuming i want to substitute "Huey" with "Daisy", should i erase the key and insert again?

Thank you very much


Last edited on
If it is one of the values in the vector, it can be directly replaced. For example,
1
2
3
map["PLUTO"].back() = "Daisy" ;
map["Jupiter"][2] = "Daisy" ;
// etc. 


If it the key that has to be changed, it has to be reinserted.
In C++17, we can do this without reallocation of the elements. For example:
1
2
3
4
5
// Change key "PLUTO" to "Mercury"
// https://en.cppreference.com/w/cpp/container/map/extract
auto node_handle = map.extract("PLUTO") ;
node_handle.key() = "Mercury" ;
map.insert( std::move(node_handle) ) ;

Snippet: http://coliru.stacked-crooked.com/a/587d68943d183507
Fantastic!

with c++14 you can't change the key, but you have to reallocate?


Yes. Something like this, to avoid copying the contents of the vector:
1
2
3
4
5
6
7
8
// Change key "PLUTO" to "Mercury" 
auto iter = map.find("PLUTO") ;
if( iter != map.end() )
{
    auto vec = std::move( iter->second ) ;
    map.erase(iter) ;
    map.emplace( "Mercury", std::move(vec) ) ;
}

Snippet: http://coliru.stacked-crooked.com/a/6a9a538bc2f24fa7


Thank you very much.
Topic archived. No new replies allowed.