Accessing element of map of vector of maps (c++) - c++

I've been working on a simple database system managment and I've come up with:
std::map< std::string, std::vector < std::map < std::string,
boost::variant <std::string, size_t, double bool> > > tables;
I have a map (tables) of vectors (table) of maps (records) and I've allready wrote a function to read a file to it but I'm not really sure how to access the single attributes.
I can print the whole thing with:
for(auto table: tables)
for(auto record : table.second)
for(auto attribute : record) {
std::cout << j.second;
I tried doing something like:
std::cout << tables["credentials"][2]["username"];
This however does not work; it only prints a blank line.

It's most likely that you are using wrong keys of the maps to access the database.
Update your code to print the contents of your database so you can see the keys also in the maps.
for(auto table: tables)
{
std::cout << "Key: " << table.first << std::endl;
for(auto record : table.second)
{
for(auto attribute : record)
{
std::cout << "Key: " << attribute.first
<< ", Value: " << attribute.second << std::endl;
}
}
}

Related

Effectively getting items from map based on specific sort

I have a fairly easy problem: I have an std::map<int,T> and another std::set<int> (can be std::vector or similar too).
In the map I store items, and in the other container I'm storing favorites (of the map).
At some point, I'd need to retrieve (all) items from the map, but starting with the favorites defined by the other container.
Here is my minimal repro, I solved it very ugly, and ineffective:
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
map<int, string> myMap;
set<int> myFavorites;
int main()
{
myMap.emplace(1, "but I don't like this");
myMap.emplace(12, "So it will go below");
myMap.emplace(31, "This one will come first, and");
myMap.emplace(44, "under my favorites");
myMap.emplace(52, "then this will follow");
myFavorites.insert(52);
myFavorites.insert(31);
cout << "My map:" << endl;
for(auto p : myMap) {
cout << "#" << p.first << "=" << p.second << endl;
}
cout << endl << "My favorites:" << endl;
for(auto p : myFavorites) {
cout << "#" << p << endl;
}
cout << endl << "All items starting with my favorites:" << endl;
for(auto p : myFavorites) {
auto item = myMap.find(p);
if (item != myMap.end()) cout << "#" << item->first << "=" << item->second << endl;
}
for(auto p : myMap) {
if (myFavorites.find(p.first) != myFavorites.end()) continue;
cout << "#" << p.first << "=" << p.second << endl;
}
}
What really bothers me is the last loop, where each iterations would call find on the set.
Required output is:
All items starting with my favorites:
#31=This one will come first, and
#52=then this will follow
#1=but I don't like this
#12=So it will go below
#44=under my favorites
Here is the above source in Coliru for making it easier: https://coliru.stacked-crooked.com/a/731fa76d90bfab00
Both map and set might be changed, but replacements needs to implement the same interfaces as originals.
I'm looking for a way to solve this more efficient than my original "brute-force" one.
Please note: map must not be "reordered"! I just need to query (retrieve) its items with custom sorting!
Note2: I know map can have a comparison operator. But I'd need to have the original order usually, and sometimes I'd need to have the custom sort!
Note3: Boost is not available and compiler is C++14 capable.
Both std::map and std::set use the same strict weak ordering for ordering its contents.
You can take advantage of this. You know that if you iterate over the map you will get the keys in the same order as they are in the set, therefore all it takes is a little bit of clever logic, something like:
auto map_iter=myMap.begin();
for(auto p : myFavorites) {
while (map_iter != myMap.end())
{
if (map_iter->first == p)
cout << "#" << map_iter->first << "=" << map_iter->second << endl;
if (map_iter->first > p)
break;
++map_iter;
}
}
It may still make sense to use find() in some edge cases, specifically when myFavorites is significantly smaller than myMap, in which case a few calls to find() might be faster than iterating over (most of) the entire map.

Storing file contents to unordered_map only storing the last items and values

I am trying to read 2000 key and value pairs from a file and store them into a unordered_map. Currently it seems to work, the only thing is that it only stores the last 200 or so into the map. I am thinking that the key and items are being overwriten because the map is not rehashing or something along those lines.
std::unordered_map<std::string, std::string> myMap;
std::ifstream infile;
infile.open("Text3m.txt");
std::string key;
std::string item;
if (infile.is_open())
{
std::string line;
while (std::getline(infile, line))
{
std::stringstream ss(line);
std::getline(ss, key, ',');
std::getline(ss, item);
myMap[key] = item;
//std::cout << key << ", " << item << std::endl;
//std::cout << key << ", " << item << std::endl;
}
}
for (auto const& n : myMap)
{
std::cout << n.first << ", " << n.second << std::endl;
}
My guess is that you have double keys in your source data. If this is the case, then you have chosen the wrong container type.
If you want to store all values distinct, then you should use a std::unordered_multimap or a std::multimap. But then you could also use a std::vector<std::pair<std::string,std::string>>.
Again a guess, you want to store keys and all found values for this key. Then you need to use a std::unordered_map<std::string,std::vector<std::string>>. For adding values, you would write
myMap[key].push_back[item];
and for the output something like
for (auto const& n : myMap)
{
std::cout << n.first << " --> " ;
std::copy(n.second.begin(),n.second.end(),std::ostream_iterator<std::string>(std::cout," "));
std::cout << "\n";
}
Please check. As said, many guesses . . .
(All code is uncompiled and untested)

Iterating over JSON ptree in boost

I need some help when iterating over JSON ptree in boost. Here's the structure.
{"drives": [{"busy": false, "eof": false, "density": 88 }]}
What I want to do is to print the key and value eg. busy = false. I've tried the code below but there is no output.
BOOST_FOREACH(ptree::value_type &v, pt.get_child("drives"))
{
cout << v.first << endl; // does not work
cout << v.second.data() << endl; // does not work
cout << v.second.get<string>("busy"); // works
}
So how do I print the key?
Thanks in advance for any help.
I went through some old code and I found the way
BOOST_FOREACH(ptree::value_type &v, pt.get_child("drives"))
{
for(auto iter = v.second.begin(); iter!= v.second.end(); ++iter)
{
std::cout << iter->first << " : " << iter->second.get_value<std::string>() << std::endl;
}
}
You only need to iterate over "drives" if you have more than one "drives", and in your json example you don't have.
In your code you try to print v.first and v.data() but those two doesn't hold the data you think they hold.
v.first supposed to hold the key name of "KeyName":{"busy": false, "eof": false, "density": 88 }
which doesn't exists because this value is part of an array.
the v.data() (If I'm not mistaken) holds the key:value which is an inner presentation and cannot be printed this way.
I really think you should try using a different framework for JSON.

How to print a map? And make it a global variable? C++

For Windows 7 64-bit
So I set up my map
map<string, string> database;
database["user"] = "123";
It's part of the main function, but how can I print the contents of the map? And most importantly how can it be turned into a global variable so I can use it by other functions? I'm trying to put my printing map process in a different function than where the map was made.
You can iterate through map with following code:
for(auto it = database.begin(); it != database.end(); ++it) {
// it->first is your key
// it->second is value of particular key
std::cout << "Key: " << it->first << std::endl;
std::cout << "Value: " << it->second << std::endl;
// value can be reached as follows as well
std::cout << "Value: " << database[it->first] << std::endl;
}
Try this:
#include <map>
#include <iostream>
// this will be a global variable
map<string, string> database;
int main()
{
database["user"] = "123";
map<string, string>::iterator it;
for(it = database.begin(); it!= database.end(); it++)
{
pair<string, string> p = *it;
cout << "key=\"" << p.first << "\" value=\"" << p.second << "\"" << endl;
}
}
I'd advise to use C++11 features, like for_each, range based begin and end and lambda:
std::for_each(std::begin(database), std::end(database),
[&database](std::pair<std::string, std::string> p) {
std::cout << "Key : " << p.first << "\tValue : " << p.second << std::endl;
});
Second I'd avoid to make your map a global variable. There are reasons for global definitions, but for a container? (This maybe depends how big your project is, but I'd say let's get rid of any global variable, and if it is really needed put it inside a namespace)
Why not encapsulate your map into a class and provide functions to alter the content of your map, even your printing facility? If you want to make sure, that every user of your class shall have the same content of the map (translated this means the same instance), you can turn your class into a singleton.
If you have C++1 available (and as a sidenote to Stefan's answer: You don't actually need std::for_each or lambdas in C++11), iteration can be done using range based for:
for ( std::pair<std::string,std::string> const &p : database)
std::cout << "key=\"" << p.first << "\" value=\"" << p.second << "\"" << std::endl;
If you want to use it in other functions, think about several things instead of making the variable global:
Aggreate/incapsulate all functions using the database in a class
Pass the map object to your functions

Accessing elements in maps of maps with vectors of shared pointers

I have a somewhat unique situation that I can't quite get working.
I've followed a lot of examples of using maps of maps but the vector of shared pointers seems to throw me off a bit.
Suppose I have the following:
typedef boost::shared_ptr<RecCounts> RecCountsPtr;
typedef std::vector<RecCountsPtr> RecCountsPtrVec;
typedef std::map<std::string, RecCountsPtrVec> InnerActivityMap;
typedef std::map< std::string, InnerActivityMap > ActivityMap;
Where RecCounts is a simple structure.
Now, I think I've figured out how to populate my ActivityMap properly.
RecCountsPtr recCountsPtr(new RecCounts());
config.actType = "M";
config.mapDate = "2010/07";
recCountsPtr->iHousehold = "50";
recCountsPtr->iZero = "150";
config.actMap[config.actType][config.mapDate].push_back(recCountsPtr);
Yes? I don't get any compile/runtime errors for this...but since I haven't figured out how to access all the different elements of the map I can't confirm this!
This is the config structure:
struct Config
{
std::string actType;
std::string mapDate;
// Map
ActivityMap actMap;
InnerActivityMap innerActMap;
//Iterator
ActivityMap::iterator actMapIter;
InnerActivityMap::iterator innerActMapIter;
};
Now, suppose I want to access each element of the ActivityMap. How would I get the following elements?
The outer map Key?
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = "
<< (*config.actMapIter).first << std::endl;
}
This seemed to do the trick.
The inner map Key?
I can't figure this out.
The inner map vector elements?
I can do it like this if I know the two keys:
config.actMap[config.actType][config.mapDate][0]->iHouehold
config.actMap[config.actType][config.mapDate][0]->iZero
...but can't seem to figure out how to iterate through them. :(
This is what I've done to try and iterate through all elements.
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
for (config.innerActMapIter = config.innerActMap.begin();
config.innerActMapIter != config.innerActMap.end();
++config.innerActMapIter)
{
std::cout << "Inner Key = "
<< (*config.innerActMapIter).first << std::endl;
for (size_t i = 0;
i < config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first].size();
++i)
{
std::cout << "iHousehold = "
<< config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first]
[i]->iHousehold << std::endl;
std::cout << "iZero = "
<< config.actMap[(*config.actMapIter).first]
[(*config.innerActMapIter).first]
[i]->iZero << std::endl;
}
}
}
I don't get any errors but I only get the outer key print to the screen:
Outer Key = M
I suspect something is amiss with my inner iterator...in that it's not associated the ActivityMap. Even if I am correct I don't know how to make such an association.
Any suggestions?
ANSWER (thanks to crashmstr):
Here is a verbose version of the answer suggested by crashmstr.
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
InnerActivityMap innerActMap = (*config.actMapIter).second;
InnerActivityMap::iterator innerActMapIter;
for (innerActMapIter = innerActMap.begin();
innerActMapIter != innerActMap.end();
++innerActMapIter)
{
std::cout << "Inner Key = " << (*innerActMapIter).first << std::endl;
for (size_t i = 0;
i < config.actMap[(*config.actMapIter).first][(*innerActMapIter).first].size();
++i)
{
std::cout << "iHousehold = "
<< config.actMap[(*config.actMapIter).first]
[(*innerActMapIter).first]
[i]->iHousehold << std::endl;
std::cout << "iZero = "
<< config.actMap[(*config.actMapIter).first]
[(*innerActMapIter).first]
[i]->iZero << std::endl;
}
}
}
I get the following printed to the screen:
Outer Key = M
Inner Key = 2010/07
iHousehold = 50
iZero = 150
When iterating over a map, .first is the "key", and .second is the data that belongs to that key.
So in your case:
for (config.actMapIter= config.actMap.begin();
config.actMapIter != config.actMap.end();
++config.actMapIter)
{
std::cout << "Outer Key = " << (*config.actMapIter).first << std::endl;
//(*config.actMapIter).second is a std::map<std::string, RecCountsPtrVec>
//create a new for loop to iterate over .second
}