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

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.

Related

Is it possible to insert a pair with a map type value into another map?

Tried looking this up but can't quite seem to find a detailed answer. Say I have a map:
std::map<int, string> categoryMap;
and I want to create a second map with keys and values that should only be accessed when associated with a specific key of the first map. The second map would also be similar:
std::map<int, string> itemMap;
I have attempted doing some sort of an insert function to try this out
categoryMap.insert(std::pair<int, map<int, string>>(itemValue, itemMap));
The error I receive claims that "no instance of overloaded function matches the argument list." Is there another way to approach this or is this just not possible?
Yes, it is possible but the type (template parameter) int, map<int, string> of the pair you are trying to insert does not match the map type int, string.
To be able to run your insert call:
categoryMap.insert(std::pair<int, map<int, string>>(itemValue, itemMap));
categoryMap has to be defined with the same template type as the item you are inserting, i.e.:
std::map<int, map<int, string>> categoryMap;
See it online.
#include <iostream>
#include <string>
#include<map>
using namespace std;
int main()
{
std::map<int, std::map<int, string>> categoryMap;
std::map<int, std::string> itemMap;
itemMap.insert(std::pair<int, std::string>(1, "abc"));
itemMap.insert(std::pair<int, std::string>(2, "xyz"));
categoryMap.insert(std::pair<int, std::map<int, std::string>>(1, itemMap));
}

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.

find a pair in set 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

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.

How to write 3d mapping in C++?

Can you please tell me how I can write multidimensional map. For two dimensional map, I did the following:
map<string, int> Employees
Employees[“person1”] = 200;
I was trying to use something similar to following for 3d mapping.
map<string, string, int> Employees;
Employees[“person1”, “age”] = 200;
Can you please tell me the correct way to do this?
and Is there a way I can initialize all the map elements to be 0 ? Just like on a array we can say int array[10]={0};
You need to create map of maps like that.
map<string, map<string, int> > employees;
employees["person1"]["age"] = 200;
You can use the pair class of the utility library to combine two objects:
map<pair<string, string>, int> Employees;
Employees[make_pair("person1", "age")] = 200;
See http://www.cplusplus.com/reference/std/utility/pair/
Instead of nested map, you can use tuple as keys; (this is a c++11 code, you could do the same with boost::tuple as well).
#include<map>
#include<tuple>
#include<string>
using namespace std;
map<tuple<string,string>,int> m;
int main(){
m[make_tuple("person1","age")]=33;
}
what you are doing here is not 3D mapping but 2D mapping, how to use stl::map as two dimension array
Correct 3D mapping will be like
map<string, map<string, map<int, string> > > Employees;
Employees[“person1”][“age”][20] = "26/10/2014";