Inserting data to somewhat complex data structure - C++ - 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.

Related

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

How to insert value in map?

I am having an issue with map.
map<int, map<int , int>> my_map;
I am using insert() like:
my_map.insert(10, my_map.second.insert(20, 30));
but it's not working.
The method to insert into map in dictionary is add(key,value)
Your code my_map.insert(10, my_map.second.insert(20, 30)); will throw an error as `second' is not a method that can be called on map.
Here is what you can do to solve this issue:
map<int, map<int , int>> my_map;
map<int, int> my__second_map = new map<int,int>();
my_second_map.add(20,30);
my_map.add(10,my__second_map);
You need an iterator of map type to call second.
You could also use below code using map insert. You may also use pair data type.
#include <map>
#include <iostream>
int main()
{
std::map<int, std::map<int , int> > my_map;
std::map<int,int> data;
data.insert(std::pair<int,int>(20,30));
my_map.insert(std::pair<int,std::map<int,int> >(10, data));
return 0;
}

How to effectively reuse mapped value

The program has the following input data:
std::map<std::string, std::vector<int> >
Now I need to convert this data structure into the following:
std::map<int, std::vector<int> >
Fo example:
"key1" => 1
"key2" => 20
etc.
Only the key type is changed, the mapped value is unchanged.
The question is that how I can reuse the mapped key std::vector<int> effectively so that the mappped value is not copied since there is no need to do so.
Here are two ideas that come to my mind:
////////////////////////////////////////////////////
Solution 1>
redefine the interface
from
std::map<int, std::vector<int> >
to
std::map<int, std::vector<int>* >
////////////////////////////////////////////////////
Solution 2>
redefine the interface
from:
std::map<std::string, std::vector<int> >
std::map<int, std::vector<int> >
to:
std::map<std::string, boost::shared_ptr<std::vector<int>> >
std::map<int, boost::shared_ptr<std::vector<int>> >
In both cases, the cost of the copy is simply a copy of a pointer.
Any comment is appreciated
C++11 provides move-operations to move one object to another without copying. VS 2010 should have the necessary machinery implemented. With this, assuming you have a mapping for old to new keys, you can remap the data like this:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (auto i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]] = std::move(i->second);
}
Now, all vectors have been moved to a new map leaving the map m1 in an undefined, but destructible state.
If C++11 (as available in VS2010) is not an option, swap the new map with the old one:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (std::map<std::string, std::vector>::iterator i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]].swap(i->second);
}

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.