how to look up hash_map in C++? - c++

Here's what I have, I am new to C++ so I am not sure if this is right...
typedef pair<string, int>:: make_pair;
hash_map <string, int> dict;
dict.insert(make_pair("apple", 5));
I want to give my hash_map "apple", and I want to get back 5. How do I do it?

hash_map is not standard C++ so you should check out the documentation of whatever library you're using (or at least tell us its name), but most likely this will work:
hash_map<string, int>::iterator i = dict.find("apple");
if (i == dict.end()) { /* Not found */ }
else { /* i->first will contain "apple", i->second will contain 5 */ }
Alternatively, if you know for sure that "apple" is in dict, you can also do: dict["apple"]. For example cout << dict["apple"]; will print out 5.
Also, why the typedef in your code? Can't you just use std::make_pair? And, it won't compile the way you wrote it (with the two leading colons)

Iterate your hashmap, vector, list and other structures:
for(hash_map<string,int>::iterator i = dict.begin(); i != dict.end(); i++)
{
cout << "key(string): " << i->first << ", value(int): " << i->second << endl;
}

Related

Is it possible to change a pair that is in a map?

So i was testing some stuff with maps and pairs and i got into a problem.
std::map<std::string, int> pairTest;
pairTest.insert(std::make_pair("Peter", 100));
for (std::map<std::string, int>::iterator it = pairTest.begin(); it != pairTest.end(); it++) {
std::cout << it->first << ":" << it->second << std::endl;
}
How can i change "Peter" to Daniel?
Am i supposed to be able to do that?
How can i make pairs never be changable and add the same key with different value?
I have tried another way, is this a more correct way of doing it?
std::map<std::string, int> pairTest;
pairTest.insert(std::pair<std::string, int>("Peter", 100));
for (std::map<std::string, int>::iterator it = pairTest.begin(); it != pairTest.end(); it++) {
std::cout << it->first << ":" << it->second << std::endl;
}
My question is, How can i change "Peter" to Daniel?
You cannot. Your best option is to remove "Peter" and then to add "Daniel".
The reason you cannot change the first of the pair, which is the key of the item, is that it is expected to be a constant from a conceptual point of view. The standard library enforces it by defining std::map<K, V>::value_type to be std::pair<const K, V>. If you are able to change the value of the first, you will destroy the sorting order of the items in the map.

How to iterate through a specific key in a map containing vector as value?

How to iterate through the contents of map["a"] to retrieve call and call1 ?
std::vector<std::string> point
std::map<std::string, point> alloc
map["a"] = call, call1
map["i"] = call
I have tried using for loop using map iterator and inside that for loop another for loop on the vector and then checking whether the value of map iterator map equals "a" but keep getting an error.
I think you are misunderstanding some syntax and of the programming language and the semantics of the standard library containers a little bit. I will explain what I think you are doing wrong.
First thing is that you have a vector of string objects called point, this is an object not a type. An object is a variable of a type, for example
string name = "curious";
Here name is an object of type/class string, so you cannot type in point as the template parameter to the map, you have to type in a type. So that should be a string.
Second thing is that you are using the comma operator, I am not sure if you knew that you were doing that. The comma operator works as follows
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
int main() {
cout << ("Hello", "World") << endl;
return 0;
}
^ this will generate a compiler error because the "Hello" is not used but the point is that the comma operator evaluates the first part of the expression and then returns the thing on the right; so this will print
World
Third thing is how you iterate through the map. When you iterate through a std::map in C++ you are actually iterating through a series of std::pairs so the following code
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <map>
using std::map;
int main() {
map<string, int> map_string_int {{"curious", 1}, {"op", 2}};
for (auto iter = map_string_int.begin(); iter != map_string_int.end();
++iter) {
cout << iter->first << " : " << iter->second << endl;
}
return 0;
}
will produce the following output
curious : 1
op : 2
the keys will be ordered alphabetically because they are stored in a binary search tree (https://en.wikipedia.org/wiki/Binary_search_tree)
Now I think you wanted to have a map from string objects to vectors, so you would structure your code as such
std::vector<string> point
std::map<string, std::vector<string>> alloc;
alloc["a"] = {"call", "call1"};
alloc["i"] = {"call"};
and you would iterate through this like so
for (auto iter = alloc.begin(); iter != alloc.end(); ++iter) {
cout << iter->first << " : " << iter->second << endl;
}
You would iterate through alloc["a"] like so
// sanity check
assert(alloc.find("a") != alloc.end());
for (auto iter = alloc["a"].begin(); iter != alloc["a"].end(); ++iter) {
cout << *iter << endl;
}
Hope that helped!
I assume you mean std::multimap instead of std::map, based on your use case (multiple values under the same key). It's in the same <map> header.
std::multimap<std::string, int> map;
map.insert(std::make_pair("first", 123));
map.insert(std::make_pair("first", 456));
auto result = map.equal_range("first");
for (auto it = result.first; it != result.second; ++it)
std::cout << " " << it->second;
Reference: std::multimap::equal_range
This should do what you want if I understand correctly.
std::vector<string> point = { "Hello", "World" };
std::map<std::string, decltype(point)> my_map;
//if you dont wan't to use decltype (or cant):
//std::map<std::string, std::vector<std::string>> my_map;
my_map["A"] = point;
my_map["B"] = { "Something", "Else" };
//this will iterate only trought my_map["A"]
for (const auto &vector_val : my_map["A"])
std::cout << vector_val << std::endl;
//this will iterate trought the whole map
for (const auto &map_pair : my_map)
{
std::cout << "map: " << map_pair.first << std::endl;
for (const auto &vector_val : map_pair.second)
std::cout << vector_val << std::endl;
std::cout << "---------------------------------" << std::endl;
}
I'm curious about knowing what is more suitable in such situations i.e multimap or map_of_vectors .
If sequencially someone want to iterate vector associated to a particular/all keys in map
what will be more efficient/optimal.
map<string ,vector<string>> mp;
// initialize your map...
for(auto itr=mp.begin(); itr!=mp.end() ;itr++)
for(auto itr2=itr->second.begin(); itr2!=itr->second.end() ;itr2++)
cout<<*itr2
for particular key just change first loop as stated down
auto itr=mp.find(key);

Find on list of map

Hello I'm working on a project and I'm a beginner in C++
I have a list of map
list<map<int,double>> voisin;
And I would like to know if it's possible to check if the element is present in my map.
This is a C# code and could you tell me how to do it in C++ please.
var res = voisin[a].Find(Map<int, double> x)
Thanks
Take a look at http://www.cplusplus.com/reference/map/map/find/
This should clear things up.
// map::find
#include <iostream>
#include <map>
int main ()
{
std::map<char,int> mymap;
std::map<char,int>::iterator it;
mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;
it=mymap.find('b');
mymap.erase (it);
mymap.erase (mymap.find('d'));
// print content:
std::cout << "elements in mymap:" << '\n';
std::cout << "a => " << mymap.find('a')->second << '\n';
std::cout << "c => " << mymap.find('c')->second << '\n';
return 0;
}
Output:
elements in mymap:
a => 50
c => 150
Use std::map::find:
std::map<int,double>::iterator it = m.find(e);
Where m is the map and e is of the same type as the keys in m.
find returns an iterator to map::end if it doesn't find the specified key.
Note that std::list in C++ is not the same as List in C#. std::list is a linked list. Use std::vector if you want a container that's equivalent to the C# List.

Print size of a vector through an iterator

I'm trying to print the size of a vector. Sounds easy, but the vector is in a map.
Currently I have an iterator on a map looking like this:
map<string, vector<map<vector<string> , vector<string> > > >::iterator it;
I am trying to display the size like this:
EDIT:
The iterator is intialised like this: it = csvMap.find(commandList.at(lineCount));
cout<<"Size of vector in Map after modifying: " << it->second.size() <<"\n"<<endl;
It's not working, the program crashes.
I think a way would be to make a temp vector and fill it with the value it->second;
But just to get the size is kind of wasting space isn't it?
Is there a better way to do so?
Thanks in advance!
EDIT2: removed old code
EDIT 3: new code:
map<vector<string> , vector<string> > parameterMap;
parameterMap.insert(pair<vector<string> , vector<string> > (
part1_input, part2_output));
map<string, vector<map<vector<string> , vector<string> > > >::iterator it;
cout<<"\nSize of CSV Map before modifying: " << csvMap.size() <<endl;
//cout<<"Size of vector in CSV Map before modifying: " << it->second.size() <<"\n"<<endl;
if(csvMap.size() == 0)
{
/*
* csvMap is empty -> no need to search for something. Just insert the fist entries
*/
listedParameterMap.insert(listedParameterMap.end(), 1, parameterMap);
csvMap.insert(pair<string, vector<map<vector<string> ,
vector<string> > > > (commandList[lineCount],
listedParameterMap));
cout<<"CSV Map size: " << csvMap.size() <<endl;
}
else
{
/*
* Search if the Command is already available, if not,
* add it to the map with its corresponding list of maps (in/output values)
* find returns map::end if key is not found
*/
cout<<"Checking if: " << commandList.at(lineCount) << " is already in the list \n" << endl;
it = csvMap.find(commandList.at(lineCount));
if (it == csvMap.end())
{
/*
* it = csvMap.end() is true
* The command isn't found
*/
cout<< commandList.at(lineCount) << " command not available. Inserting it! \n" << endl;
listedParameterMap.insert(listedParameterMap.end(), 1, parameterMap);
csvMap.insert(pair<string, vector<map<vector<string> ,
vector<string> > > > (commandList[lineCount],
listedParameterMap));
}
else
{
/*
* it != csvMap.end()
* The command is found. Append the parameterMap to the vector in the map
*/
cout<< commandList.at(lineCount) << " is already in the list! Appending parameters on pos: "<< it->second.size()-1<< "\n" << endl;
it->second.push_back(parameterMap);
}
}
cout<<"\nSize of CSV Map after modifying: " << csvMap.size() <<endl;
cout<<"Size of vector in CSV Map after modifying: " << it->second.size() <<"\n"<<endl;
I hope someone is still reading this...
I found now that it.second seems to be the problem on the first interation. But I don't get why.
Code snippet (also in the code above):
if(csvMap.size() == 0)
{
/*
* csvMap is empty -> no need to search for something. Just insert the fist entries
*/
listedParameterMap.insert(listedParameterMap.end(), 1, parameterMap);
csvMap.insert(pair<string, vector<map<vector<string> ,
vector<string> > > > (commandList[lineCount],
listedParameterMap));
cout<<"CSV Map size: " << csvMap.size() <<endl;
cout<<"listedParameterMap: " << listedParameterMap.size() <<endl;
cout<< commandList.at(lineCount) << " is already in the list! Appending parameters on pos: "<< it->second.size()<< "\n" << endl;
}
This seems not to work. Although its goning into it. Any idea why?
comanndList and listedParameterMap are as far as I see OK.
it = csvMap.find(commandList.at(lineCount));
if (it == csvMap.end()) {
cout << "not found\n";
}
else {
cout << "Size of vector in Map after modifying: " << it->second.size() << '\n';
}
Either when command isn't found or command is the last
No, the end iterator is not an item in the container.
string c = (*it).first;
Since this is after the iterator is the end iterator, you have undefined behavior when dereferencing it.
Your it is pointing to an invalid location. You need to initailize it with the map's iterator. Something like it = myMap.find("aaa"); //Replace it with actual key After doing the find you need to make sure you are having a valid iterator by checking it agains myMap.end().
EDIT
You are using uninitialized iterator here:
cout<<"Size of vector in CSV Map before modifying: " << it->second.size() <<"\n"<<endl;
Also, you can not dereference a iterator pointing csvMap.end(), it will result in crash again.
As per EDIT 3
You are still using the unitialized iterator / iterator pointing to end in if(csvMap.size() == 0) and if(it == csvMap.end()) case. You need to initialize the it with the return value of insert function like this:
it = csvMap.insert(....).first; in these cases.
Map iterators aren't invalidated unless you erased that specific element. That means that you did something else wrong.
Your collection is rather complex.
In order to check the size though you need to know there is an element there at all, i.e. find did not return "end" of your map. If it does, you cannot use the iterator returned.
Of course how you handle this is your own decision, eg return maybe -1 if the string was not found (with 0 indicating it was found but had no content).
Now you have edited your code I immediately spot a bug:
if (it == csvMap.end())
{
/*
* it = csvMap.end() > true
* Either when command isn't found or command is the last
*/
string c = (*it).first;
you cannot dereference end (which it is)

I need to have a key with multiple values. What datastructure would you recommend?

I have an string array filled with words from a sentence.
words[0] = "the"
words[1] = "dog"
words[2] = "jumped"
words[3] = "over"
words[4] = "the"
words[5] = "wall."
words[6] = "the"
words[7] = "cat"
words[8] = "fell"
words[9] = "off"
words[10] = "the"
words[10] = "house."
etc.
(Stupid example, but it works for this)
Each word will be a key with it's following word as it's value. so "over" => "the". Some keys can have multiple values. For example, "the" => "dog" || "wall" || "cat" || "house". The value is randomly chosen from those for that key.
When the program runs it picks a word at random and makes a sentence. So it could be something like: "the cat fell off the dog".
I tried implementing a map (map myMap;) but this allows only one value per key (I think).
Hope I explained this right.
std::multimap
The link provides an excellent example. Quoted below:
int main()
{
multimap<const char*, int, ltstr> m;
m.insert(pair<const char* const, int>("a", 1));
m.insert(pair<const char* const, int>("c", 2));
m.insert(pair<const char* const, int>("b", 3));
m.insert(pair<const char* const, int>("b", 4));
m.insert(pair<const char* const, int>("a", 5));
m.insert(pair<const char* const, int>("b", 6));
cout << "Number of elements with key a: " << m.count("a") << endl;
cout << "Number of elements with key b: " << m.count("b") << endl;
cout << "Number of elements with key c: " << m.count("c") << endl;
cout << "Elements in m: " << endl;
for (multimap<const char*, int, ltstr>::iterator it = m.begin();
it != m.end();
++it)
cout << " [" << (*it).first << ", " << (*it).second << "]" << endl;
}
If you're using C++ then just create a class to represent your key-value pairs:
Class foo {
key : String
values : list of values
}
Then, create a map that maps each key to an object containing its values.
This is simple, extendable, and can be done in any OO-language.
Sorry, my C++ is rusty so the syntax is wrong, but the essential idea is straightforward.
you can use a multimap from the STL and use the call
pair<iterator, iterator> equal_range(const key_type& k)
to get a range of iterators that match your key
personally i find this slightly clunky due to having to deal with iterator ranges rather than just getting an object back that represents all values for that key. to get around that you could also store a vector in a regular map and add your strings to the vector.
I've found that a struct may work well for this situation. This approach (basically akin to a class) allows a cleaner access to your parameters named as you see fit.
struct car_parts {
string wheelType;
string engine;
int number_of_cylinders;
car_parts(string _wheelType, string _engine, int _number_of_cylinders)
{
wheelType = _wheelType;
engine = _engine;
number_of_cylinders = _number_of_cylinders;
}
};
int main()
{
// Populate the dictionary
map<char, car_parts> vehicles =
{
{ 'I', car_parts("All terrain", "X2", 6) },
{ 'C', car_parts("Summer only", "BB", 8) },
{ 'U', car_parts("All terrain", "X3", 4) }
};
map<char, car_parts>::iterator it;
it = vehicles.find('I');
if (it != vehicles.end())
{
cout << "The vehicle with key of I has " << it->second.number_of_cylinders << " cylinders\n";
}
}
There can be an alternate approach to achieve two values per key, especially for the cases when most of the map elements have two values per key. By pairing two values for a key, as mentioned in this link:
std::map<std::string, std::pair<std::int, int> > myMap2
use it in the function as:
#include<iostream>
#include<map>
#include<iterator>
using namespace std;
int main(){
map<string,pair<int,int>>mp;
mp.insert(pair<string,pair<int,int>>("ab",make_pair(50,7)));
mp.insert(pair<string,pair<int,int>>("cd",make_pair(51,8)));
map<string,pair<int,int>>::iterator it;
for(it=mp.begin();it!=mp.end();it++)
cout<<it->first<<" "<<it->second.first<<" "<<it->second.second<<" ";
return 0;
}
As two others pointed out, std::multimap can be your solution.
Also consider std::tr1::unordered_multimap. It is available in VS 2008 seems to have it, GCC has it at least from version 4.3.
You may also use unordered_map<char,vector<string>> which has some benefit over map structure. You can do such insertion if your dictionary is like 'c': "cat", 'c':"car", 'a':apple, 'a':"angus" :
unordered_map<char, vector<string>> char_to_strings_map;
//loop to traverse the dictionary : key:c, value:s
char_to_strings_map[c].emplace_back(s);
//loop ends