Defining maps in class - c++

I am new to C++ and am not able to correctly define maps in class definition.
Here is the code I have written:
#include<stdio.h>
#include <iostream>
#include <map>
#include <utility> // make_pair
#include <string.h>
#include <sstream>
using namespace std;
class assgnt
{
private:
//typedef std::map<int, int> MapType;
//MapType my_map;
public:
bool isGoodPoint(int x, int y);
void addGoodNeighbours(int x, int y);
};
inline bool assgnt::isGoodPoint(int x, int y)
{
string xs, ys;
stringstream xout, yout;
int xsum=0, ysum=0;
xout<<x; yout<<y;
xs = xout.str();
ys = yout.str();
for each (char c in xs)
{
xsum = xsum + int(c);
}
for each (char c in ys)
{
ysum = ysum + int(c);
}
if (xsum+ysum <= 19)
return true;
else
return false;
}
inline void assgnt::addGoodNeighbours(int x, int y)
{
//if assgnt::isGoodPoint(x+1,y)
if(isGoodPoint(x+1,y))
{
}
/*if isGoodPoint(x+1,y) and [x+1,y] not in points: points.append([x+1,y])
if isGoodPoint(x-1,y) and [x-1,y] not in points: points.append([x-1,y])
if isGoodPoint(x,y+1) and [x,y+1] not in points: points.append([x,y+1])
if isGoodPoint(x,y-1) and [x,y-1] not in points: points.append([x,y-1])*/
}
int main()
{
typedef std::map<int, int> MapType;
MapType my_map;
// insert elements using insert function
my_map.insert(std::pair<int, int>(0, 0));
int i=0;
while true
{
//my_map.insert(std::pair<int, int>(2, 2));
//my_map.insert(std::pair<int, int>(3, 3));
//my_map.insert(MapType::value_type(4, 4)); // all standard containers provide this typedef
//my_map.insert(std::make_pair(5, 5)); // can also use the utility function make_pair
MapType::iterator iter = my_map.begin();
std::cout << "Size of my_map: " << my_map.size() << '\n';
std::cout << "Enter a key to search for: ";
int c;
std::cin >> c;
iter = my_map.find(c);
if (iter != my_map.end())
{
int num = iter->second;
if(num == 0)
std::cout << "Value is found: " << iter->second << '\n';
else
std::cout << "Value not found: ";
}
else
std::cout << "Key is not in my_map" << '\n';
// my_map.clear();
}
I wish to define the map typedef std::map MapType; in the class definition, so that I can use it in all inline functions and the main() by creating its object.
Please help.

I suppose you want to use it outside of the class? Define it in a public section and be happy. Typedefs are absolutely safe from encapsulation point of view, they are just synonyms. Then you can use it in main as assgnt::MapType.

It looks like your compilation problems are not with your map, but your while syntax:
-while true
+while(true)
{
+}

To get your code to work, you need to fix a few problems:
Your class needs a public constructor
Make your map public.
When using your map outside the class, use the type assgnt::MapType
This will give you working code so you can try out whatever you're doing. I guess that's what your question was? That you could not get it working inside the class?
There are a few other errors in your code, but you should be able to figure those ones out ;)

Your while loop contains an error: it should be
while(true)
{
//...
}
Infinete loop is a bad idea (your program won't terminate) - you didn't coded any conditional statement like
while(true)
{
//...
if(some_condition)
break;
}
You need to make your my_map field public, so that you can access it from main (as well as the other procedures).
And finally instantiate your class:
int main()
{
assgnt obj;
//...
// now write obj.my_map instead of just my_map
}

Related

Generating a map of strings to std::list of pointers in c++

I am trying to achieve the creation of such a map. The following code attempts to do this
#include <list>
#include <map>
#include <string>
class IntWithString {
private:
int a;
std::string s;
public:
IntWithString(int a, std::string s) : a(a), s(s) {}
std::string getString() { return s; }
int getInt() { return a; }
};
namespace {
std::map<std::string, std::list<IntWithString *> > m;
}
void appendMap(IntWithString *a) {
auto it = m.find(a->getString());
if (it != m.end()) {
m[a->getString()].push_back(a);
} else {
std::list<IntWithString *> l;
l.push_back(a);
m[a->getString()] = l;
}
}
int main() {
IntWithString a(10, "ten");
IntWithString b(11, "ten");
appendMap(&a);
appendMap(&b);
return 0;
}
However when looking at the map m with the debugger I am getting a map that maps "ten" to a list of size 0. What I would like is a list of size 2.
I am not sure what you mean. If I do:
std::cout << m.size() << ", " << m["ten"].size() << std::endl;
I get this output:
1, 2
which is a map with one key ("ten"), and two values for that key (10 and 11), as expected.
Live demo
PS: Storing pointers in a container like this is a bit uncommon in C++. If you really want to do this though, consider to use Smart Pointers.

iterating over vector of vectors in c++

I've just started to code in C++, so i'm new to STL .
Here i'm trying to iterate over a graph stored as vector of vectors.
#include <iostream>
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*it) << endl;
if ((*it) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
I'm getting an error std::vector<int> is not derived from const gnu cxx. Can someone point me in the right direction ?
*it pointing to vector not int that is why you are getting error
following code may work for you
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*(*it).begin()) << endl;
if (( (*(*it).begin())) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
for accessing first element of the vector of the use
(*(*it).begin()) in place of (*it)
if you are studying graph then use array of vector. for more details please go through following url
C++ Depth First Search (DFS) Implementation
cout << (*it) << endl;
Here, you declared it as a:
vector<vector<int> >::iterator it;
Therefore, *it is a:
vector<int>
So you are attempting to use operator<< to send it to std::cout. This, obviously, will not work. This is equivalent to:
vector<int> v;
cout << v;
There is no operator<< overload that's defined for what cout is, and a vector<int>. As you know, in order to print the contents of a vector, you have to iterate over its individual values, and print its individual values.
So, whatever your intentions were, when you wrote:
cout << (*it) << endl;
you will need to do something else, keeping in mind that *it here is an entire vector<int>. Perhaps your intent is to iterate over the vector and print each int in the vector, but you're already doing it later.
Similarly:
if ((*it) == x)
This won't work either. As explained, *it is a vector<int>, which cannot be compared to a plain int.
It is not clear what your intentions are here. "Graph stored as a vector or vectors" is too vague.
The following code compiles with the option std=c++11. But x is missing in vector<vector<int>>. If adj had type vector<pair<int, vector<int>>> it would better match.
The following code compiles for vector<vector<int>> but it doesn't use x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
// cout << (*it) << endl;
for (const auto& nexts: *it)
cout << nexts << ' ';
cout << endl;
for(i=(*it).begin();i!=(*it).end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
This code compiles with <vector<pair<int, vector<int>>> and uses x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<pair<int, vector<int> > > &adj, int x, int y) {
vector<pair<int, vector<int> > >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
cout << it->first << endl;
if (it->first == x)
for(i=it->second.begin();i!=it->second.end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
Wrap it up in an iterator.
This can be templated for reuse.
Here is a minimal working example for the std::vector<T> container:
#include <iostream>
#include <utility>
#include <vector>
/// Iterable vector of vectors
/// (This just provides `begin` and `end for `Vector2Iterable<T>::Iterator`).
template<typename T>
class VovIterable
{
public:
static const std::vector<T> EMPTY_VECTOR;
/// Actual iterator
class Iterator
{
typename std::vector<std::vector<T>>::const_iterator _a1;
typename std::vector<T>::const_iterator _a2;
typename std::vector<std::vector<T>>::const_iterator _end;
public:
/// \param a1 Outer iterator
/// \param a2 Inner iterator
/// \param end End of outer iterator
explicit Iterator(typename std::vector<std::vector<T>>::const_iterator a1, typename std::vector<T>::const_iterator a2, typename std::vector<std::vector<T>>::const_iterator end)
: _a1(a1)
, _a2(a2)
, _end(end)
{
Check();
}
bool operator!=(const Iterator &b) const
{
return _a1 != b._a1 || _a2 != b._a2;
}
Iterator &operator++()
{
++_a2; // Increment secondary
Check();
return *this;
}
const T &operator*() const
{
return *_a2;
}
private:
void Check()
{
while (true)
{
if (_a2 != _a1->end()) // Is secondary live?
{
break;
}
// Increment primary
_a1++;
if (_a1 == _end) // Is primary dead?
{
_a2 = EMPTY_VECTOR.end();
break;
}
_a2 = _a1->begin(); // Reset secondary
}
}
};
private:
std::vector<std::vector<T>> _source;
public:
explicit VovIterable(std::vector<std::vector<T>> source)
: _source(std::move(source))
{
}
/// Start of vector of vectors
[[nodiscard]] Iterator begin() const
{
if (this->_source.empty())
{
return end();
}
return Iterator(this->_source.cbegin(), this->_source.cbegin()->cbegin(), this->_source.cend());
}
/// End of vector of vectors
[[nodiscard]] Iterator end() const
{
return Iterator(this->_source.cend(), EMPTY_VECTOR.end(), this->_source.cend());
}
};
template<typename T>
const std::vector<T> VovIterable<T>::EMPTY_VECTOR = {0};
/// Sample usage
int main()
{
std::vector<std::vector<int>> myVov{{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
for (int i: VovIterable(myVov))
{
std::cout << i << std::endl;
}
return 0;
}

Loop over a structure of vector<string> in C++

Question: Is there a better way to loop through all the vectors in the structure than by calling them one by one as shown in the example? #
I am building a classifier. There are several categories of items each represented by a vector of string. Each of the vectors will be fairly small, < 100 elements. I have read the examples in the following link:
How to find if an item is present in a std::vector?
Here is a simplified example of the code that I am implementing. The code compiles and runs but seems clunky to me. Thanks in advance.
#include "stdafx.h"
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct Categories
{
vector <string> cars;
vector <string> food;
};
struct ThingsType
{
Categories iLike;
Categories dontLike;
};
typedef vector<string>::const_iterator vIter;
int FindValue(vector<string>& vec, string keyWord)
{
int indx = -1;
vIter iter = find(vec.begin(), vec.end(), keyWord);
if (iter != vec.end()){
// found it
std::cout << "Value: " << *iter << " found in location: " << iter - vec.begin() << endl;
indx = iter - vec.begin();
}
else
{
// did not find it.
std::cout << "Value: " << keyWord << " not found." << endl;
}
return indx;
}
int _tmain(int argc, _TCHAR* argv[])
{
int result[10];
ThingsType things;
things.iLike.cars = { "Mustang", "Pinto" };
things.dontLike.food = { "Squash" };
string item("Pinto");
// I want to loop over all vectors searching for items
result[0] = FindValue(things.iLike.cars, item);
result[1] = FindValue(things.iLike.food, item);
// . . .
result[9] = FindValue(things.dontLike.food, item);
return 0;
}
You can keep the struct, and store pointers to each struct member in a list or vector.
struct Categories
{
vector <string> cars;
vector <string> food;
};
std::vector<std::vector<string>*> members;
Categories cat;
members.push_back(&cat.cars); // add a pointer to the cars struct member
members.push_back(&cat.food); // add a pointer to the food struct member
Now you can iterate via members, or access via the struct.
for(std::vector<string>* member: members)
{
for(string s: *member)
{
}
}
Or you could just forego the structure altogether and use the vector of vectors, that way you can iterate the "members" while still allowing O(1) access time for each member.
const int CARS = 0;
const int FOOD = 1;
members[CARS].push_back(car); // add a car
members[FOOD].push_back(food); // add food
// iterate cars
for(string car: members[CARS])
{
// do something
}
Try using a std::map
using namespace std;
typedef set<string> CategoryType;
struct ThingsType
{
map<string, CategoryType> iLike;
map<string, CategoryType> dontLike;
};
int _tmain(int argc, _TCHAR* argv[])
{
ThingsType things;
things.iLike['cars'].insert("Mustang");
things.iLike['cars'].insert("Pinto");
things.iLike['food'].insert("Squash");
string item("Pinto");
// I want to loop over all vectors searching for items
for(map<string, CategoryType>::const_iterator i = things.iLike.begin(); i != things.iLike.end(); i++) {
if (i->second.find(item) != set::end)
cout << "I like " << item << endl;
}
for(map<string, CategoryType>::const_iterator i = things.dontLike.begin(); i != things.dontLike.end(); i++) {
if (i->second.find(item) != set::end)
cout << "I don't like " << item << endl;
}
return 0;
}
I think std::unordered_set would be better in this case.
#include<unordered_set>
struct Categories{
std::unordered_set <std::string> cars;
std::unordered_set <std::string> food;
};
struct ThingsType{
Categories iLike;
Categories dontLike;
};
int main(){
std::unordered_set<std::string>::iterator result[10];
ThingsType things;
things.iLike.cars = { "Mustang", "Pinto" };
things.dontLike.food = { "Squash" };
string item("Pinto");
result[0] = things.iLike.cars(item);
result[1] = things.iLike.food(item);
// . . .
result[9] = things.dontLike.food(item);
}

C++ Map with two keys of different values

I need a map which can have two keys, of different data types, yet point to the same struct.
struct DataStruct {
SomeEnum keyEnum; // <---- key as enum
std::string keyString; // <----- a key as a string
int arbitrarydata;
int moredata;
}
Then I want a std::map I can look up like:
std::map<SomeEnum||std::string, DataStruct> dataMap;
dataMap[SomeEnum::AValue] = dataStruct1;
dataMap["mykey"] = dataStruct2;
Is this even possible or do I need to make 2 maps? Seems a waste. Or do I need to overload an operator or something?
You can use std::pair, like this:
#include <iostream>
#include <map>
#include <utility>
typedef enum {A, B, C} en;
int main ()
{
en myen = A;
std::map<std::pair<char,int>, int> mymap;
mymap.insert ( std::pair<std::pair<char, int>,int>(std::make_pair('a',myen),200) );
mymap.insert ( std::pair<std::pair<char, int>,int>(std::make_pair('z',30),400) );
// showing contents:
std::cout << "mymap contains:\n";
for (std::map<std::pair<char,int>, int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << "(" << it->first.first << ", " << it->first.second <<
") => " << it->second << '\n';
return 0;
}
Not an answer in the question:
Note, that in C++11, you can use enum class, which in general can be more useful.
A std::map can only have keys of the same type, but you can trick it with whatever key logic you want. Just be sure that they can compare properly:
struct DataStruct {
struct Key {
std::string keyString;
SomeEnum keyEnum;
int type;
Key(SomeEnum a) : keyEnum(a), type(0) { }
Key(const char * a) : keyString(a), type(1) { }
bool operator<(const Key & o) const {
if (type != o.type) return type < o.type;
else return type == 0 ? keyEnum < o.keyEnum : keyString < o.keyString;
}
};
int data;
}
Then you can use it almost the way you wanted:
std::map<DataStruct::Key, DataStruct> dataMap;
dataMap[SomeEnum::AValue] = dataStruct1;
dataMap["mykey"] = dataStruct2;
You need to be sure that keys of different types don't point to the same data, thats why I first order them by type and then by their value.

Inserting typedef map into a hash table

In the program below I've a typedef map. What I want to do is to implement a hash table. I'm trying to use unordered_map since I heard that is the efficient as it takes O(1) time. I use my typedef map everywhere in my main program (another program that I'm working on) so I don't want to change that. I want to implement hash table in one of the functions and I'm trying to figure out how to insert the contents of my map into the hash table and search for the key later. I've inserted a comment in two places where I'm having trouble. Please help.
#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>
using namespace std;
typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;
int main(){
m_t sample;
for (int i = 0; i < 100; i = i+2) {
v_t v;
for(int k = 100 ; k<=105 ; ++k)
v.push_back(k);
s_t k;
k.insert(i);
sample.insert(sample.end(), make_pair(k, v));
}
//---------Debug--------------------
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
cout << "Key: ";
copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
cout << " => Value: ";
copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
cout << endl;
}
//---------------------------------
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
c1.insert(Mymap::value_type(it->first,it->second)); // how to do this ?
}
s_t s;
s.insert(72);
if(c1.find(s)!=c1.end()) // does this work ?
cout << "Success" << endl;
return 0;
}
I appreciate any help or comments.
After reading Jason's comments I understand why i cannot use a std::set as a key in unordered_map so I tried to use std::string as a key but the find function won't work. Could you please help me.
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
v_t v1;
std::string key;
key.insert(key.begin(),it->first.begin(),it->first.end());
copy(it->second.begin(), it->second.end(),std::back_inserter(v1));
c1.insert(Mymap::value_type(std::make_pair(key,v1)));
}
string s = "72";
if((c1.find(s) != c1.end()) == true)
cout << "Success" << endl;
return 0;
The basic element you're missing to make this work is to define a hashing function for your std::set that you're using as the key. The STL already defines equality and lexicographical ordering for a std::set, so you can use it as the key-value in a std::map as-is without any problems. It does not define a hash function though, so that is something you're going to have to-do by overloading std::hash. This is fairly straight-forward, and can be done by defining the following function:
namespace std
{
template<>
struct hash<std::set<int> > : public std::unary_function<std::set<int>, size_t>
{
size_t operator()(const std::set<int>& my_set) const
{
//insert hash algorithm that returns integral type
}
};
}
The above functor object would return an integral type of size_t, and would take a std::set as the argument. You'll have to define it inside of namespace std so that std::unordered_map will recognize it. An "easy" algorithm could be simply summing the elements since you have a set of type int. There are more complex algorithms out there that would reduce the number of collisions such a simple algorithm would create at the expense of hashing time. Once you have this defined though, you shouldn't have any problems inserting your std::set key-values into an unordered_map, as well as creating new key-values and finding them in the hash table.
You can see an example of your source-code working at: http://ideone.com/DZ5jm
EDIT: Jason's code placed here for reference:
#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>
using namespace std;
namespace std
{
template<>
struct hash<set<int> > : public unary_function<set<int>, size_t>
{
size_t operator()(const std::set<int>& my_set) const
{
set<int>::iterator iter = my_set.begin();
int total = 0;
for (; iter != my_set.end(); iter++)
{
total += *iter;
}
return total;
}
};
}
typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;
int main(){
m_t sample;
for (int i = 0; i < 100; i = i+2) {
v_t v;
for(int k = 100 ; k<=105 ; ++k)
v.push_back(k);
s_t k;
k.insert(i);
sample.insert(sample.end(), make_pair(k, v));
}
//---------Debug--------------------
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
cout << "Key: ";
copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
cout << " => Value: ";
copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
cout << endl;
}
//---------------------------------
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
c1.insert(Mymap::value_type(it->first,it->second)); // how to do this ?
}
s_t s;
s.insert(72);
if(c1.find(s)!=c1.end()) // does this work ?
cout << "Success" << endl;
return 0;
}