how to print a Map Object? - c++

sorry if my question is to newbish, but i cant find a solution.
i have a class named Transition that have a map called inNext, and i want to print this Transition object, but i get an error about "cant find the begin or end members" (from map class)
class Transition{
public:
Transition():inNext(){};
~Transition(){};
map<string, string>& getTransition(){
return inNext;
}
void setTransition(string a, string b){
inNext.insert(pair<string,string>(a,b));
}
void printTransition(Transition a){
map <string, string>::iterator it;
for(it = a.begin(); it != a.end(); it++){
cout << (*it).first << ","<<(*it).second << endl;
}
}
private:
map<string, string> inNext;
};

Your method is weird: It's a member function and it takes another instance of Transition (and even copies it for no reason) as an argument. You probably want
void print() {
// you want to print the content of the map inNext:
for(map <string, string>::iterator it = inNext.begin(); it != inNext.end(); it++) {
cout << it->first << "," << it->second << endl;
}
}
which is called like this:
Transition myTransition = ...;
myTransition.print();

begin and end are members of std::map not of your class. You need to call a.inNext.begin() and a.inNext.end().

Related

How to print a nested map-map-vector

I am having issues loading and printing my map-map-vector data structure. I think it's on the printing side, since I am not 100% sure how to use iterators.
I created and loaded the data into the structure to store my data here:
(I created inner_test and myvector because it looked like I needed them for the iterators. I'm not sure how the iterators know that inner_test and myvector are part of test though.)
map<int, map<string, vector<string>>> test;
map<string, vector<string>> inner_test;
vector<string> myvector;
ifstream thisfile;
const char *file1 = argv[1];
thisfile.open(file1);
string filler;
while( thisfile >> filler ){
string sortedFiller = filler;
sort(sortedFiller.begin(), sortedFiller.end());
test[filler.length()][sortedFiller].push_back(filler);
}
thisfile.close();
I tried to print it with this, but I don't think I quite understand what I'm doing here.
map<int, map<string, vector<string>>>::iterator itr1;
map<string, vector<string>>::iterator itr2;
vector<string>::iterator itr3;
for(itr1 = test.begin(); itr1 != test.end(); itr1++){
cout << itr1->first;
for(itr2 = inner_test.begin(); itr2 != inner_test.end(); itr2++){
cout << itr2->first;
for(itr3 = myVector.begin(); itr3 != myVector.end(); itr3++){
cout << *itr3;
}
}
cout << endl;
}
Your inner_test, and my_vector variables are empty containers, and are unrelated to the actual std::map, you want to print, in any way. This is one of the examples how can you print multidimensional container:
// auto type automatically defines itself as a return type of test.begin ()
for(auto itr1 = test.begin(); itr1 != test.end(); itr1++)
{
cout << itr1->first << ' '; // Add space to separate entries on the same line
// itr1->second represents map<string, vector<string>> stored in test.
for(auto itr2 = itr1->second.begin (); itr2 != itr1->second.end (); itr2++)
{
cout << itr2->first << ' ';
// itr2->second represents vector<string> stored in map<string, vector<string>> which is stored in test.
for(auto itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++)
{
cout << *itr3 << ' ';
}
}
cout << endl;
}
Use auto to deduce type of iterators automatically like for(auto itr1 = container.begin(); ....
Then, before second loop, add const auto& inner_test = itr1->second; and iterate over your nested map like you did.
Similarly, before third loop, add const auto& myVector = itr2->second;.
What is going on here.
In C++ it's possible to overload * and -> operators. Iterators do that.
When you iterate over std::map, iterator points std::pair of references to key and value. Pair has first and second fields which are, in this case, references to key and value respectively.
Also, use .cbegin() and .cend() -- const iterators -- if you don't want to alter data in 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);

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

how to iterate through a set of sets C++

Pretty new to C++, only at it a week or so, I want to iterate through a set of nested sets and write each element in the inner set to a line in a file.
Each inner set has 3 elements and I want all three elements on the same line.
I have a set up as follows:
// Define "bigSet" and initiate as empty set "Triplets"
typedef set < set<string> > bigSet;
bigSet Triplets;
I tried something of this sort to go through it but it gives me an error...
// Iterate through and print output
set <string>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); it++){
cout << *it << endl;
}
Any help is greatly appreciated guys thank you!
I would do it this way:
// Iterate through and print output
set < set <string> >::iterator it_ex; // iterator for the "outer" structure
set <string>::iterator it_in; // iterator for the "inner" structure
for(it_ex = Triplets.begin(); it_ex != Triplets.end(); it_ex++)
{
for(it_in = it_ex->begin(); it_in != it_ex->end(); it_in++)
cout << *it_in << ", ";
cout << endl;
}
Triplets is not a set<string>; it is a set<set<string>>; each item in Triplets is itself a set, than can contain several strings.
The iterator must match the type of the container; with two levels of nested containers, you should iterate twice:
set<set<string>>::iterator it;
set<string>::iterator it2;
for(it = Triplets.begin(); it != Triplets.end(); it++) {
for (it2 = it->begin(); it2 != it->end(); ++it2) {
cout << *it2 << endl;
}
}
Triplets is type set < set<string> > and therefore requires an iterator of type set < set<string> >::iterator or bigSet::iterator. It isn't type set <string>. You could also use const_iterator.
Note that iterating Triplets gives you an iterator to another set, and not a string.
Also consider
for (const auto& i : Triplets)
{
for (const auto& j : i)
{
cout << j << endl;
}
}
You have an error because Triplets.begin() is not of type set<string>::iterator, it's set<set<string>>::iterator.
What you need to do is have two loops: one for iterating over the outer set and one for the inner.
set<set<string>>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); ++it)
{
set<string>::iterator it2;
for(it2 = it->begin(); it2 != it->end(); ++it2)
{
cout << *it2;
}
cout << endl;
}
If you use increment/decrement operators (++/--) on iterators, it might be better to use the prefix versions (++it) instead of the suffix ones (it++). This is because the suffix ones create a copy of the iterator before it is incremented (and that copy is then returned) but in cases like this, you have no need for it.
Moreover, if you're using C++11, you can use the range-based for loops and auto keyword, which simplify things a lot:
for(const auto &innerSet : Triplets)
{
for(const auto &innerSetElement : innerSet)
{
cout << innerSetElement;
}
cout << endl;
}
First: if they're triplets, are you sure that std::set is the type you
want for the inner values. Perhaps a class would be more
appropriate, in which case, you define an operator<< for the `class,
and your simple loop works perfectly. Something like:
class Triplet
{
std::string x;
std::string y;
std::string z;
public:
// Constructors to enforce that none of the entries are identical...
// Accessors, etc.
friend std::ostream& operator<<( std::ostream& dest, Triplet )
{
dest << x << ", " << y << ", " << z;
return dest;
}
};
And then to output:
for ( Triplet const& elem : Triplets ) {
std::cout << elem << std::endl;
}
Otherwise: you need to define the format you want for the output. In
particular, you'll probably want a separator between the strings in the
line, for example. Which means you probably cannot use a range based
for, at least not for the inner loop. You would need something like:
for ( std::set<std::string> const& triplet : Triplets ) {
for ( auto it = triplet.cbegin(); it != triplet.cend(); ++it ) {
if ( it != triplet.cebegin() ) {
std::cout << ", ";
}
std::cout << *it;
}
std::cout << std::endl;
}
(If the set of triplets is large, you'll definitely want to consider
replacing std::endl with '\n'. But of course, if it is really
large, you probably won't be outputting to std::cout.)

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