Iterating and using find() in a map c++ - c++

I have a map storing a "job" as a key and a "name" as the value it stores.
map<string, string>dutyAndJob;
map<string,string>::iterator it;
I'm basically trying to look through this map for a particular "name".
If the name isn't there, it shouldn't enter this loop, however, for some unknown reason, it always enters this loop:
string name = "Bob";
it = dutyAndJob.find(name);
if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
For some reason, it would still enter this loop even though there isn't a Bob stored in the map.
Any help would be greatly appreciated!

if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
should be:
if (it != dutyAndJob.end()) // Does it refer to a valid association
{
cout << "Testing : " << name << endl;
}
Notice the change from == to != indicating that the key was found in the map. The iterator it is only equal to dutyAndJob.end() if the key was not found.

Just realized that Job is the key, and Name is the data. The way you have it structured, you can only use find on the Job that will retrieve the Name.
string job = "Cashier";
it = dutyAndJob.find(job);
if (it == dutyAndJob.end())
{
cout << "Testing : " << job<< endl;
}
If you actually wanted to search by Name, maybe the Name should be the key, and the Job should be the data?

Related

How do I check whether an index of array is empty and then, if it is, skip to the next?

I'm trying to build a program that can register a user to the database (still learning cpp, I hope that in the near future I'll be able to work with database).
What I'm trying to do with this code is to check whether an index of array is empty for the user to store an ID in it. If it isn't empty, I want the program to keep looking for an empty index of array, for the new info to be stored in.
Here is the code:
void registro() {
std::string userid[3];
userid[0] = "Houkros"; // eventually I'll try to have this being read from a file or server database..
std::string userpass[3];
std::string usermail[3];
std::string userkey[3];
std::string getUid[3];
std::string getUpass[3];
std::string getUmail[3];
std::string getUkey[3];
std::cout << std::endl << " >>>> REGISTRATION <<<< " << std::endl;
std::cout << " =============================================== " << std::endl;
std::cout << std::endl;
std::cout << "Please, enter the desired user id: " << std::flush;
if (userid[0].empty())
{
std::cin >> userid[0];
}
else {
std::cin >> userid[1];
}
for (int i = 0; i < 2; i++)
{
std::cout << " Element of array: " << i << " is > " << userid[i] << std::endl;
}
Please consider the following definitions for an "empty" array element:
a) not initialised (unhelpful, cannot be checked)
b) never yet written to (same as a) )
c) contains "" (possible, but means that "" must not be accepted as an actual content)
d) is empty according to a second array in which that info is maintained (this is what I almost recommend)
e) contains a struct with a string and a maintained "empty" flag (this I recommend)
Whatever you do, make sure that you init all variables and array elements before first read-accessing them; i.e. in all cases first write something meaningful to it.

Reading Json file's root in c++ with jsoncpp

File:
{
"somestring":{
"a":1,
"b":7,
"c":17,
"d":137,
"e":"Republic"
},
}
how can I read the somestring value by jsoncpp?
Use the getMemberNames() method.
Json::Value root;
root << jsonString;
Json::Value::Members propNames = root.getMemberNames();
std::string firstProp = propNames[0];
std::cout << firstProp << '\n'; // should print somestring
If you want to see all the properties, you can loop through it using an iterator:
for (auto it: propNames) {
cout << "Property: " << *it << " Value: " << root[*it].asString() << "\n";
}
This simple loop will only work for properties whose values are strings. If you want to handle nested objects, like in your example, you'll need to make it recursive, which I'm leaving as an exercise for the reader.

Simplify Do While Loop Checking for Null Pointer

I have a really basic problem that I can't figure out. I'm using chaining with hash tables to store nodes that collide with each other. I used a do while loop to print the first node at least once, and continue to print the chained nodes if they exist. However, in order to traverse the chained list, I need to change the address of the node for the next loop. Any way I try writing this, I find myself repeating code, which I was trying to avoid by using this loop. Please help
do {
cout << "Bid id: " << table.at(i)->bidId << " title: " << table.at(i)->title <<
" fund: " << table.at(i)->fund << " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next!=nullptr){//check if first node has next node
table.at(i) = table.at(i)->next; //change address to the next pointer
}// how do I avoid repeating my condition below?
}
while (table.at(i)->next!=nullptr);
This code will replicate the functionality in your loop without duplicating the check against NULL.
while(true)
{
cout << /* stuff */ endl;
auto next = table.at(i)->next;
if(next)
table.at(i) = next;
else
break;
}
From the description though, are you sure you want to reassign the values inside your hash map while looping over them? I suspect that this code may suit your intent/needs better:
auto current = table.at(i);
while(current)
{
cout << /* stuff */ endl;
current = current->next;
}
When you find yourself in a situation like this one, it's a good idea to question your premise. In this case, I am talking about your assumption that you need a do while loop.
If there is a chance that your data won't be there or that your container is empty, then a do while won't do the job because it will loop at least once.
Generally, for iterating through a collection of data you'll want to use a for or while loop.
If I understand the code correctly, you need a precondition loop and not a postcondition one, as you have right now. For example:
while (table.at(i)) {
cout << "Bunch of stuff";
table.at(i) = table.at(i)->next;
}
You could try doing:
for(auto node = table.at(i)->next;node!=nullptr;node=node->next)
cout << "Bid id: " << node->bidId << " title: " << node->title;
Where you may need to replace node = table.at(i)->next with an appropriate way of getting a link to the first entry.
You can use C++11's range based for loop here. All you want to know is that value->next is not a nullptr before doing the assignment. Rest all is taken care by the simple and modern range based for loop
for(auto const& value: table) {
if (value->next != nullptr) {
value = value->next;
}
}
Its even faster and safer this way
If really you want to be able to get last element after the loop, you may do:
do {
cout << "Bid id: " << table.at(i)->bidId
<< " title: " << table.at(i)->title
<< " fund: " << table.at(i)->fund
<< " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next == nullptr){
break;
}
table.at(i) = table.at(i)->next;
} while (true);
// table.at(i) != nullptr && table.at(i)->next == nullptr

TinyXML2 EXC_BAD_ACCESS Im sure its a null ptr but no idea why

So I have been at this for days, and I have no idea why a BAD_ACCESS error is thrown. Sometimes it works, sometimes it doesn't.
void xmlParser::parseXML(string file){
tinyxml2::XMLDocument doc;
if(!doc.LoadFile(file.c_str()))
{
cout << "ERROR: TINYXML2 FAILED TO LOAD" << endl;
}
//XML FILE LAYOUT:
//<item>
// <type id="laserWeapon" name="Laser Rifle">
// <tooltip>
// <stats>
//</item>
//error seems to occur on this line
tinyxml2::XMLElement* elementType = doc.FirstChildElement("item")->FirstChildElement("type");
string id = elementType->Attribute("id");
string name = elementType->Attribute("name");
cout << "id: " << id << endl;
cout << "name: " << name << endl;
}
I use
xmlparser.parseXML(xmlparser.path+"laserRifle.xml");
to load the file. Should I be parsing this as a string, or is there some null ptr I'm neglecting? I've tried to do an 'if nullptr' clause, but it still turns out an error instead of skipping over it.
Any advice on what to do? I'm completely lost with this.
// item element can be missed and you'll get bad access. Do not chain your calls that way
tinyxml2::XMLElement* elementType = doc.FirstChildElement("item")->FirstChildElement("type");
// element type can be missed, as well as attributes id and name
string id = elementType->Attribute("id");
string name = elementType->Attribute("name");
cout << "id: " << id << endl;
cout << "name: " << name << endl;
}
Carefully check every element and attribute. Do not chain calls because every call can return null. If you check all nullptr cases you'll find your error

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.