hash_map< vector<int>, int> error when using find function - c++

struct HASH_CMP {
bool operator()(vector<int> V, vector<int> W) const {
for(int i = 0; i < 10; i++)
if(V[i] != W[i]) return false;
return true;
}
};
hash_map< std::vector<int>, int, HASH_CMP > H;
long long inHash(const vector<int> &V) {
if(H.find(V) == H.end()) return -1; //this line
return H[V];
}
I have declared the following hash, given the comparing class above and I receive an error at the line mentioned saying:
no match for call to '(const HASH_CMP) (const std::vector<int, std::allocator<int> >&)
I need some help on fixing this code.

The third template argument is the hash functor. The comparison functor is the fourth template argument. Thus you need:
hash_map<std::vector<int>, int, HASH_HASH, HASH_CMP>
And you still need to write HASH_HASH.
(I recommend you look at Boost's hash_range implementation for inspiration.) Also note that equality for vectors is already defined (and more efficiently than your version) and shouldn't require self-written code.

As the error is telling you, you need a hashing function that takes a const std::vector<int>& and returns a size_t. To put something in a hash map, there has to be some way to hash it.
This will work:
size_t operator()(const vector<int>& vec)
{
size_t v = 0;
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
v = (v ^ *it) * 0x9e3779b9;
return v;
}

Related

Iterate through a pointer set that contains string vectors in C++

This is my declaration of the set:
set< vector<string> >* tuples = new set< vector<string> >();
And this is how I am trying to iterate through it:
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); it++){
if(it[column] == value){
rowResults->insert(*it);
}
}
but I get an error
no match for ‘operator[]’ (operand types are ‘std::set<std::vector<std::__cxx11::basic_string<char> > >::iterator {aka std::_Rb_tree_const_iterator<std::vector<std::__cxx11::basic_string<char> > >}’ and ‘int’)
if(it[column] == value){
^
You're applying [] to the iterator instead of to the object to which it points. You need to dereference the iterator (and mind operator precedence!):
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); ++it){
if((*it)[column] == value){
rowResults->insert(*it);
}
}
Note that with iterators, it's better to use ++it instead of it++ in loops, since the latter can be less efficient under insufficient optimisation.
it is an iterator, not the vector object itself. To access the vector object just use *it
Even better: get rid of the confusing iterator type by defining a reference (here constant ref since we don't seem to need a non-const) to the element itself.
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); it++){
const vector<string> &v = *it; // more readable
if(v[column] == value){
rowResults->insert(v);
}
}
as no decent C++ answer cannot not mention the "new" C++11, note that if you use -std=c++11 option, the syntax is much better to iterate on a list
for(auto v : *tuples)
{
if(v[column] == value){
rowResults->insert(v);
}
}
You may avoid iterator with something like:
std::set<std::vector<std::string>>
computeRowResult(const std::set<std::vector<std::string>>& input,
int column,
const std::string& value)
{
std::set<std::vector<std::string>> rowResults;
for (const auto& v : input) {
if (v[column] == value) {
rowResults.insert(v);
}
}
return rowResults;
}
or avoiding the manual loop with
std::set<std::vector<std::string>>
computeRowResult(const std::set<std::vector<std::string>>& input,
int column,
const std::string& value)
{
std::set<std::vector<std::string>> rowResults;
std::copy_if(input.begin(), input.end(),
std::inserter(rowResults, rowResults.end()),
[&](const auto& v) { return v[column] == value; });
return rowResults;
}
Demo

Error: no match for 'operator[]' (operand types are 'std::list<std::pair<int, int> >*' and 'std::pair<int, int>')

I am trying to create a graph where each node is a pair of two int values. For this I have created a list adj of type pii (pair<int, int>). Now when I try to push_back a pii type node in the list it says
error: no match for 'operator[]' (operand types are 'std::list<std::pair<int, int> >*' and 'std::pair<int, int>')|
Here's my code. ( I haven't added the edges from main() yet). I've included all the necessary headers. I've searched but can't find a similar error.
#define pii pair<int, int>
#define lli long long int
using namespace std;
class graph
{
lli v;
list<pii> *adj;
public:
graph(lli v);
void addEdge(pii n, pii m);
void bfs(pii s);
};
graph::graph(lli v)
{
this->v = v;
adj = new list<pii >[v];
}
void graph::addEdge(pii n, pii m)
{
adj[n].push_back(m); //Error Line
}
void graph::bfs(pii s)
{
bool visited[v];
memset(visited, false, sizeof(visited));
list<pii> q;
list<pii>::iterator it;
q.push_back(s);
while(!q.empty())
{
pii temp = q.front();
q.pop_front();
for(it = adj[temp].begin() ; it != adj[temp].end() ; it++)
{
if(!visited[*it])
{
visited[*it] = true;
q.push_back(*it);
}
}
}
}
int main()
{
int n, m, i, j;
pii coordinates;
cin>>n>>m;
char input[n][m];
for(i = 0 ; i < n ; i++)
{
for(j = 0 ; j < m ; j++)
{
cin>>input[i];
make_pair(i, j);
}
}
graph(n*m);
return 0;
}
adj is of type std::list<std::pair<int, int>>*, which is a pointer. Pointers implement the following operator[]
T & operator[](T *, std::ptrdiff_t);
You're trying to call the following:
T& operator(T*, std::pair<int, int>);
You need to call operator[] with a type of std::ptrdiff_t which is a signed integer.
void graph::addEdge(***int*** n, pii m)
{
adj[n].push_back(m); //Error Line
}
As others have said, the direct answer to your question is that you are attempting to index a pointer with a pii (which you have #defined as pair<int,int>), and since a pii has no automatic conversion to an integer, it cannot be used as an index.
Looking at the broader picture, because of your abbreviated variable and method names, it is hard to see what it is you are trying to do. Is your intent that adj be an array of lists? If so, you just need to change the first parameter to addEdge to int, so that it can be used as an index into this array. But from a quick look through the method bfs, it looks like perhaps adj is intended to just be a list, in which case you can remove the asterisk from its declaration and eliminate its assignment in the graph constructor, and eliminate the indexing altogether. Or if what you are trying to do is to map one pii to another pii, you would need to use something like std::map instead of std::list.

(c++) can't iterate over a vector in a key hasher function

I'm trying to implement my own hash function for a simple object, say a vector of integers :
struct Key
{
std::vector<int> vec;
bool operator==(const Key &other) const
{ return (vec == other.vec); }
};
struct KeyHasher
{
std::size_t operator()(const Key& k) const
{
using std::size_t;
std::size_t res = 0;
std::vector <int>::iterator i;
for (i = k.vec.begin(); i != k.vec.end(); ++i)
{/* hash code */}
return res;
}
};
... but I can't iterate over k.vec. The line
for (i = k.vec.begin(); i != k.vec.end(); ++i)
is rejected by g++ :
'no match for operator=' (operand types are 'std::vector<int>::iterator [...]'
What's going on ? This syntax would be ok in another context : where's my error ?
i needs to be const_iterator: k, and therefore k.vec, is const here. (Better still, use auto.)
try using const_iterator instead of iterator.
k is const.
std::vector <int>::const_iterator i;
otherwise you will need to remove the constness...

C++ map::find for pair as key

I have a map of pair as key and bool as value. When i try to find a certain pair that is already included using map::find method, it's not finding any item. What do i do wrong?
I tried to implement a comparator class and set it as key_comp in map, but I'm not sure i did it right. Is this the solve?
I am working in VS12, I attached a photo with the debugging, you shall understand much more from that:
You are calling find with pair<char *, char*>(0x00ffc468, 0x00ffbdb0). There is no such pair in the set, so find returns end.
Your code compares char *'s, which checks if they point to the same place in memory, not whether they point to identical content. You should probably use std::string instead of char * rather than reinventing wheels.
Here's an example of a possible comparison function you could use if you insist on doing so:
bool less(
std::pair<char *, char *> const& p1,
std::pair<char *, char *> const& p2)
{
int i = strcmp (p1.first, p2.first);
if (i < 0)
return true;
if (i > 0)
return false;
return strcmp (p1.second, p2.second) < 0;
}
If you must use std:pair<char*, char*> as key in your map, you can use the following functor while creating the map.
struct MyCompare
{
bool operator()(std::pair<char const*, char const*> const& lhs,
std::pair<char const*, char const*> const& rhs)
{
int n1 = strcmp(lhs.first, rhs.first);
if ( n1 != 0 )
{
return n1 < 0;
}
return (strcmp(lhs.second, rhs.second) < 0);
}
};
typedef std::map<std::pair<char*,char*>, int, MyCompare> MyMap;
MyMap myMap;

can't assign iterator to constant input vector in a binary function

I am trying to write a binary function that takes two vectors(of the same length) and adds them by value. For some reason the following code does not work:
struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> >
{
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
std::vector<int> ret(x);
std::vector<int>::iterator itx,ity;
ity=y.begin();
for (itx=ret.begin();itx<ret.end();++itx)
{
ret[*itx]+=y[*ity];
++ity;
}
return ret;
}
};
I get an error that I can't do ity=y.begin()
However, the following code does work
struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> >
{
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
std::vector<int> ret(x);
std::vector<int> yloc(y);
std::vector<int>::iterator itx,ity;
ity=yloc.begin();
for (itx=ret.begin();itx<ret.end();++itx)
{
ret[*itx]+=yloc[*ity];
++ity;
}
return ret;
}
};
Obviously, the second version will take longer (since it has to copy an additional vector). Is it because the input is a const vector? If it is, is there any reason it needs to be? Note that I am planning on using this function as an input to the allreduce() function in boost::mpi if that makes any difference
You define ity as vector::iterator y is const and returns a const_iterator.
What is more important is: Don't use binary_function. The adapters have been deprecated.
Also, your function does not do what you want. *itx returns the value stored at the position pointed to by itx and you use it to index into the you intend to return vector.
I would write this with a binary transform.
std::vector<int> res;
std::transform(begin(x), end(x), begin(y),
std::back_inserter(res), std::plus<int>());
The error is that you cannot use non-const iterators with a const container, as that would break const-correctness. You should use std::vector<int>::const_iterator on the second argument.
Other than that, the implementation in the first block does not do what you claim it does.You are iterating over the container and using the stored values to index into the container and update there. If you actually want to add the values from the two containers, it is much simpler than that:
struct PlusVal
{
std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
{
assert( lhs.size() == rhs.size() );
for (std::vector<int>::size_type i = 0; i < lhs.size; ++i )
lhs[i] += rhs[i];
return lhs;
}
};
If you want to do that with iterators, it is again similarly simple:
struct PlusVal
{
std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
{
assert( lhs.size() == rhs.size() );
std::vector<int>::iterator it = lhs.begin(), end = lhs.end();
std::vector<int>::const_iterator rit = rhs.begin();
while ( it != end )
*it++ += *rit++;
return lhs;
}
};
You're looking for the std::vector::const_iterator type
std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y)
{
std::vector<int> result;
// Not strictly necessary, but helps with performance a bit
result.reserve(std::min(x.length(), y.length());
for (std::vector<int>::const_iterator x_it = x.begin(),
y_it = y.begin();
x_it != x.end() && y_it != y.end();
++x_it, ++y_it)
{
result.push_back(*x_it + *y_it);
}
return result;
}
It looks like you've already gotten a reasonable answer or two; I'll just point out an alternative. Though I hesitate to mention it, std::valarray fits so well for this I just can't resist:
std::valarray<int> x;
std::valarray<int> y;
// code to populate x and y elided
x += y;
Ever few months (or so) I see something valarray would make so simple I find it truly regrettable that it's been lost and forgotten (then I think about things like slice, gslice, slice_array, indirect_array, etc., and wish I hadn't thought of it at all).