find a pair in set c++ - c++

if I have a set which contains pairs of int,
set<pair<int,int> > cells;
how can I find whether a pair exits in the set using 'find'. I can use 'find' for set with one value but cant do it for a pair.
I am trying like,
cells.insert(make_pair(1,1));
set<int,int>::iterator it;
it=cells.find(pair<int,int>(1,1));
error: no match for 'operator=' in 'it = cells.std::set<_Key, _Compare, _Alloc>::find<std::pair<int, int>, std::less<std::pair<int, int> >, std::allocator<std::pair<int, int> > >((*(const key_type*)(& std::pair<int, int>((* &1), (* &1)))))'|
Has anyone got any ideas? Thanks!

The problem is that your set is a set of a pair of integersstd::pair<int,int>, instead of just <int,int>. Changing that fixes your code. If you are using c++11 or later you can just use the auto keyword.
// Example program
#include <iostream>
#include <string>
#include <utility>
#include <set>
int main()
{
std::pair<int,int> p1(1,0);
std::pair<int,int> p2(2,1);
std::set<std::pair<int,int>> s;
s.insert(p1);
s.insert(p2);
auto it = s.find(p1);
std::cout << it->first << "," << it->second <<std::endl;
}

There seems to be a typo/misunderstanding about the type to be used for it. You need to use:
std::set<std::pair<int,int>>::iterator it;

It should be:
std::set<std::pair<int,int>> cells;
cells.insert(std::make_pair(1,1));
std::set<std::pair<int,int>>::iterator it; // here was the problem
it=cells.find(std::pair<int,int>(1,1));
In order to avoid these kind of mistakes you may use auto:
std::set<std::pair<int,int>> cells;
cells.insert(std::make_pair(1,1));
auto it =cells.find(std::pair<int,int>(1,1));
If you have to separate the definition and the use of it:
decltype(cells)::iterator it;
it=cells.find(std::pair<int,int>(1,1));
Live Demo

Related

Inserting data to somewhat complex data structure - C++

I have a following data structure:
std::map<std::string,std::vector<std::map<std::string,std::vector<std::map<std::string,double> > > > >
So a map containing string as a key and as a value a list of maps, that have again string as a key and list of maps as a value.
Is there a way to insert data using one liner. (Im not aware what this technique is called.
What I mean is that in python i could do:
datas={"key":[{"key2":[{"key3":234}]}]}
I tried this:
ostokset.insert({ketju,{{kauppa,{{tuote,hinta}}}}});
But it didn't work.
Please don't do this! It is completely unreadable and unmaintainable.
That being said, here is the solution to your question:
m["key1"] = {{{"key2", {{{"key3", 234.}}}}}};
To reach this solution I basically created initializers for each type, from the innermost (easiest) to the outermost (most complex):
std::map<std::string, double> map_x = {{"key3", 234.}};
std::vector<std::map<std::string, double>> v_x = {map_x};
std::map<std::string,
std::vector<std::map<std::string, double>>> map_y = {{"key2", v_x}};
std::vector<std::map<std::string,
std::vector<std::map<std::string, double>>>> v_y = {map_y};
And then started to construct the solution backwards by replacing each variable with its initialization:
m["key1"] = v_y;
m["key1"] = {map_y};
m["key1"] = {{{"key2", v_x}}};
m["key1"] = {{{"key2", {map_x}}}};
m["key1"] = {{{"key2", {{{"key3", 234.}}}}}};
You have to consider an extra bracket for the std::pair inside the std::map
#include <cstdio>
#include <map>
#include <string>
#include <vector>
int main() {
std::pair<std::string, double> a{"s1", 1.0};
std::map<std::string, double> b{{"s2", 2.0}};
std::vector<std::map<std::string, double>> c{{{"s1", 3.0}}};
std::map<std::string, std::vector<std::map<std::string, double>>> d{
{"s2", {{{"s1", 4.0}}}}};
std::vector<
std::map<std::string, std::vector<std::map<std::string, double>>>>
e{{{"s2", {{{"s1", 5.0}}}}}};
std::map<std::string,
std::vector<std::map<std::string,
std::vector<std::map<std::string, double>>>>>
f{{"s3", {{{"s2", {{{"s1", 6.0}}}}}}}};
printf("%f\n", b["s2"]);
printf("%f\n", f["s3"][0]["s2"][0]["s1"]);
return 0;
}
And compile with at least C++11.

set/access jagged map values made with map<string, boost::any>

I've been shown how to create a jagged multidimensional std::map by using boost::any.
However, I'm having trouble setting the values like in this answer.
When I use
accounts["bank"]["cash"] = 100;
gcc gives this error
error: no match for ‘operator[]’ in ‘accounts.std::map<_Key, _Tp, _Compare,
_Alloc>::operator[]<std::basic_string<char>, boost::any,
std::less<std::basic_string<char> >, std::allocator<std::pair<const
std::basic_string<char>, boost::any> > >((* & std::basic_string<char>(((const
char*)"bank"), (*(const std::allocator<char>*)(& std::allocator<char>())))))["cash"]’
How can a jagged multidimensional map created with boost::any be accessed? (If there is a better technique to do this, please show me. I only care about what works and is quick to write.)
multidimensional declaration
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
json-spirit
I gave up and tried to use json-spirit's mObject instead since all of this seems already built in.
Funny thing is is that with the exact same notation, I get the exact same error.
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
Of course this cause compile time error, you put to boost::any std::map,
but compiler have no idea about this. accounts["bank"] has "boost::any" type,
and boost::any have no
int& operator[](const char *)
Read how boost::any works: http://www.boost.org/doc/libs/1_54_0/doc/html/any/s02.html
Fix is trivial:
#include <boost/any.hpp>
#include <map>
#include <string>
int main()
{
std::map<std::string, boost::any> accounts;
accounts["cash"] = 100;
accounts["bank"] = std::map<std::string, boost::any>();
boost::any_cast<std::map<std::string, boost::any> &>(accounts["bank"])["cash"] = 100;
}
How did you define your accounts map? As boris said, you need to nest two maps together in order to do what you want.
Replace the type string with boost::any
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, map<string, string>> accounts;
accounts["bank"]["cash"] = "infinity";
cout << accounts["bank"]["cash"];
return 0;
}
How does this work?
Maps are key and value pairs.
accounts["bank"] returns the value of the outermost map, which corresponds to
map<string, **map<string, string>**>
accounts["bank"]["cash"] returns the value of the innermost map, which corresponds to
map<string, map<string, **string**>>
Defining a 1 dimensional map does not allow you to do what you want, but 2 dimensional maps do.

alias used not modifying the actual contents of STL container

I am unable to understand the following behaviour. When I use currPMap to modify the value, the value at the actual location is not modified. Why is that so.
I checked with the reference the operator[] and at() return reference and so this should have worked.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef map<int, int> intMap;
typedef map<int, int>::iterator mapIt;
int main(void) {
vector< map<int, intMap > > b(2);
int curr=0, next=1;
map<int, intMap> currPMap = b.at(curr);
(currPMap[4])[2] = 3; //modified by currPMap.
cout<<((b.at(curr))[4])[2]<<endl;
((b.at(curr))[4])[2] = 3; //modified using the actual vector.
cout<<((b.at(curr))[4])[2]<<endl;
}
Output:
0
3
P.S.: I know what I am doing here can be achieved by many other ways in this setting, but this is not the actual program. This is just the explicit version of the problem that I am facing with my code. I would be grateful if someone answers what is wrong in this method.
Because you are getting a copy of a map here, not an alias:
map<int, intMap> currPMap = b.at(curr); // currMap is a copy of b[0]
You then modify the copy, not the map stored in the vector.
What you need is a reference:
map<int, intMap>& currPMap = b.at(curr); // currMap refers to b[0]
map<int, intMap> currPMap = b.at(curr);
That's not an alias (aka reference); that's a copy. If you want a reference, you need to declare it thusly:
map<int, intMap> & currPMap = b.at(curr);
^
Beware that the reference may be invalidated if you add or remove elements to the vector, since vectors need to move their elements to maintain a contiguous array.

Accessing member variables through boost lambda placeholder

I'm trying to print the second member variable of all items in an stl map using a lambda expression
map<int, int> theMap;
for_each(theMap.begin(), theMap.end(),
cout << bind(&pair<int, int>::second, _1) << constant(" "));
but this is not compiling. I essentially want to de-reference the placeholder. Any idea what I'm missing here?
Thanks in advance!
Try:
for_each(theMap.begin(), theMap.end(),
cout << bind(&map<int, int>::value_type::second, _1) << constant(" "));
std::map will add const to its key; this is to prevent messing up the ordering. Your pair should be:
std::pair<const int, int>
Like dirkgently suggests, use the value_type to always get the correct type. The verbosity is alleviated with a typedef:
typedef std::map<int, int> int_map;
int_map::value_type::second

BOOST_FOREACH & templates without typedef

When I work with BOOST_FOREACH, there isn't a problem with simple templates as vector. But when I try to iterate through map > for example I need to typedef the element type.
Is there any workaround?
There is a problem because it is a macro, and therefore cannot handle types containing commas (preprocessor doesn't know about templates).
You can also declare the variable before the loop, see documentation.
std::map<int, double> my_map;
//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }
//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }
Edit:
There is a further complication with std::map in particular: the value_type is not std::pair<Key, Value>, but std::pair<const Key, Value>.
Hence, if you go with the typedef, a more proper way (and the only way if you want to use a reference in the foreach loop) is to use
typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;
BOOST_FOREACH(MyPair& ref, my_map) { ... }
However, that won't work if you want to use a variable declared before the loop, since you can't assign to a std::pair<const int, double> instance later (can't assign to the const field), in which case you can only use pair<int, double> as boost's manual shows.
If you need to iterate over a map, the easiest way is to use tuples, since getting the correct type in order to typedef, is troublesome. Here is how you can use tuples:
std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }
Just a note, the commas will work here because parenthesis are placed around key and value. The preprocessor only understands commas and parenthesis(and c99 requires it to understand quotation marks also). So, it can't parse the <> in std::pair<int, double>. However, we can use parenthesis to help the preprocessor. For example, if we have a a function that returns a container that is called like this:
BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile
So, we can place parenthesis around an expression and it will help the preprocessor:
BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile
However, in the case of a map, we can't place parenthesis around the declaration(because its not an expression). So this won't work:
BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work
Because it will get transformed into something like this (std::pair<int, double> p) = *it, and that, of course, is incorrect C++. But using a tie will work:
BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work
We just need to declare key and value outside of the loop(as shown above). Plus, it can make the loop have more meaningful names. You can write key instead of p.first, and value instead of p.second.
BOOST_FOREACH_PAIR is another option that works well in our experience:
http://lists.boost.org/Archives/boost/2009/09/156345.php
http://lists.boost.org/Archives/boost/2009/09/156366.php
This can be as simple as this:
BOOST_FOREACH(auto& p, my_map) { ... }
Using the C++11 standard, auto is like var in C#, it will do
BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }