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

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.

Related

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);

Iterating in to the set of strings which are the values in map

#include <iostream>
using namespace std;
void insertValue(map<string, set<string> >& myMap,
string const& key,
string const& value)
{
// Check whether there is already a set given the key.
// If so, insert to the existing set.
// Otherwise, create a set and add it to the map.
map<string, set<string> >::iterator found = myMap.find(key);
if (found != myMap.end())
{
cout << "Adding '" << value << "' to an existing set of " << key << "s.\n";
found->second.insert(value);
}
else
{
cout << "Adding '" << value << "' to a new set of " << key << "s.\n";
set<string> temp;
temp.insert(value);
myMap.insert(make_pair(key, temp));
}
}
int main()
{
map<string, set<string> > filemap;
insertValue(mymap, "file1", "path1");
insertValue(mymap, "file1", "path2");
insertValue(mymap, "file1", "path3");
insertValue(mymap, "file2", "path1");
insertValue(mymap, "file3", "path2");
return 0;
}
Can anyone tell me how I can iterate through the set of strings, given a key in the above map???? or do I have to place an iterator in the value ....I can't understand how can I go this this further
The easiest way to iterate over the map is by using a range-based for instead of using iterators
for(auto const& kv : mymap) {
for(auto const& v : kv.second) {
std::cout << kv.first << ": " << v << '\n';
}
}
kv is a const& to your map's value_type, which is std::pair<const std::string, std::set<std::string>>. The nested for statement is then iterating over the second element in the pair.
And if you really want to use iterators, then use this
for(auto miter = mymap.cbegin(); miter != mymap.cend(); ++miter) {
for(auto siter = miter->second.cbegin(); siter != miter->second.cend(); ++siter) {
std::cout << miter->first << ": " << *siter << '\n';
}
}
That aside, your function for inserting values can be simplified quite a bit. There's no need to check whether an element already exists in a map before inserting a value because map::operator[] will construct the key you pass to it if one doesn't already exist, and the corresponding value type will be value initialized. So your insertValue function becomes a one-liner.
void insertValue(map<string, set<string> >& myMap,
string const& key,
string const& value)
{
myMap[key].insert(value); // default construct a set for a new key
}
Finally, unless you need the values corresponding to a key be ordered, you can use a multimap instead. This container is just like a map, but you can have several values corresponding to a single key value. However, unlike your solution, the order of the values which have identical keys is the order of their insertion.
Live demo

check if a key is found in a map c++ and obtains it

I want to check if a certain key is found in a map, if so i want to put it in a variable for other uses, but the thing is I dont want to use iterators. I found the find function in the map class, but it returns an iterator, I want to like check if a key is found in map, if it returns true to obtain it
Thanks
std::map::count() will inform you if the map contains a particular key. If the key is in the map, then you could use operator[] to get at the value, knowing that a default value will not be added (though as ildjarn points out would require two searches of the map):
std::map<int, int> m;
m[0] = 1;
m[1] = 2;
if (m.count(0))
{
std::cout << "value=" << m[0] << "\n";
}
Why find() is unattractive, is not clear to me:
std::map<int, int>::iterator i = m.find(0);
if (i != m.end())
{
std::cout << "value=" << i->second << "\n";
}

Two dimensional unordered_map

typedef boost::unordered_map<int, void*> OneDimentionalNodes;
typedef boost::unordered_map<int, OneDimentionalNodes> TwoDimentionalNodes;
TwoDimentionalNodes nodes;
is this valid?
i don't use any hash functions since keys of the unordered_maps' are single integers.
it compiles, but when i iterate it like this, it crashes while trying to access this->hash_function()(k);
for (TwoDimentionalNodes::iterator it= nodes.begin(); it != nodes.end() ; ++it)
{
for(OneDimentionalNodes::iterator it2 = nodes[it->first].begin(); it2 != nodes[it->first].end() ; ++it2)
{
// do stuff
}
}
i'm also open to other containers with
O(1) access
O(n) iteration
Sparse
If you just need to iterator over all elements, and it is not required to loop over a specific dimension, then you could use a simple pair as key for your unordered_map, like this:
typedef std::pair<int,int> Coordinates;
typedef std::unordered_map<Coordinates,void *> TwoDimensionalNodes;
(notice I used STL instead of Boost, unordered_map is now also part of the standard STL).
Getting a specific value is simply writing:
twoDimensionalNodes[std::make_pair(x,y)]
(or use find if you're not sure if that value is in your map).
To iterate, just iterate over the unordered map:
for (auto it=twoDimensionalNodes.begin();it!=twoDimensionalNodes.end();++it)
{
std::cout << "x=" << it->first.first;
std::cout << "y=" << it->first.second;
std::cout << "value=" << it->second;
}
To make it a bit more readable, I prefer getting the coordinates first from the iterator, like this:
for (auto it=twoDimensionalNodes.begin();it!=twoDimensionalNodes.end();++it)
{
Coordinates &coordinates = it->first;
std::cout << "x=" << coordinates.first;
std::cout << "y=" << coordinates.second;
std::cout << "value=" << it->second;
}
If you have more than 2 dimensions, use std::tuple, or simply write your own Coordinates class to be used as key for the map.
Use std::unordered_map from <unordered_map>.
Try to specialize std hash class this way:
namespace std
{
template<typename T>
struct hash<void*>
{
std::size_t operator()(void * ptr) const
{
return (std::size_t)ptr;
}
};
}

how to look up hash_map in 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;
}