Bool function to compare two list of structs - c++

This bit of code below is reading in a stringstream and adding each piece to a struct, and once its done its adds the whole struct to a list of structs.board is the temporary struct and then
while (getline(ss, word, ',')){
if (wordIndex==0){
board.item = word;
}
else if (wordIndex==1&&word==" for sale"){
board.forSale = false;
}
else if (wordIndex==1&&word==" wanted"){
board.forSale = true;
}
else if (wordIndex==2){
board.price = atoi(word.c_str());
}
wordIndex++;
}
index ++;
messageBoard.push_back(board);
I also have this function im trying to create that compares the contents of board, with the contents of array. Not sure if I need to compare it with an iterator or just compare the items individually.
bool compare(struct messageBoard* one, struct messageBoard* two){
return(one.item==two.item&&one.forSale!=two.forSale&&one.price<=two.price)
}
Thats as far as I've gotten. The goal is if Item matches and the forSale values are opposites(True vs False) and the price of the for sale is <= to the wanted item, then the bool function returns True, else it returns false. I want to run it right before the
arr.push_back(board);

Related

Continue a while loop until EOF (Qt)

I'm working on a program to create a list from a large QStringList. So basically after a string match, a while loop will start to add the next strings into a list. This part is working fine. The only problem I have is that the program quits unexpectedly because I don't know how I should add the EOF mechanism.
Update with a more detailed code
Sorry for not providing with enough details about my code. This is how my code looks now. So after the first time the string "PACKAGE TYPE" is detected, I use the function storeLines() function to store the next strings into one of three lists dependent. And this will continue until the next "PACKAGE TYPE" match or EOF. The only thing that is not working correctly now is when the iterator is on the last string of the QStringList. It somehow doesn't detect that the next is inputline.end()
void storeLines(QString department, QStringList::iterator current_line, QStringList::iterator endline){
while(QString::compare(*(current_line + 1),"PACKAGE TYPE") && (++current_line != endline)){ //this is not working
if(!QString::compare(department, "MDA")) mda_list.push_back(*current_line);
else if(!QString::compare(department, "SDA")) sda_list.push_back(*current_line);
else mix_list.push_back(*current_line);
}
}
void void MainWindow::on_pushButton_clicked(){
QString input = ui->listinput->toPlainText().toLatin1();
QStringList inputline = input.split("\n", QString::SkipEmptyParts );
for(QStringList::iterator pkg_header(inputline.begin()); pkg_header != inputline.end(); ++pkg_header){
if(!QString::compare(*pkg_header,"PACKAGE TYPE")){
++pkg_header;
if(!QString::compare(*pkg_header,"Department-mda:")) storeLines("MDA", pkg_header, inputline.end());
else if(!QString::compare(*pkg_header,"Department-sda:")) storeLines("SDA", pkg_header, inputline.end());
else storeLines("MIX", pkg_header, inputline.end());
}
}
}
Thanks in advance!
You're writing a parser - it's often simplest to write it like you'd usually write one, by making the states explicit and iterating in sequence over every element of the input stream. You won't make any off-by-one iterator errors that way.
This code matches the intent in your question, and makes it obvious that you've missed a case: when you expect a department, you don't react to the PACKAGE TYPE being present. You could signal an error, or stay in the DEPARTMENT state, but I presume you should handle it and not just ignore it.
QStringList mda_list, sda_list, mix_list;
void parse(const QString & input) {
enum {
TYPE,
DEPARTMENT,
ITEMS
} state = TYPE;
auto list = &mix_list;
auto const kPackageType = QStringLiteral("PACKAGE TYPE");
for (auto const element : input.split("\n", QString::SkipEmptyParts)) {
switch (state) {
case TYPE:
if (element == kPackageType)
state = DEPARTMENT;
break;
case DEPARTMENT:
if (element == QStringLiteral("Department-mda:"))
list = &mda_list;
else if (element == QStringLiteral("Department-sda:"))
list = &sda_list;
state = ITEMS;
break;
case ITEMS:
if (element == kPackageType)
state = DEPARTMENT;
else
*list << element;
break;
}
}
}
The use of QStringLiteral gives you compile-time-built string instances to compare against. The code would work about just as well if you removed the QStringLiteral(...) wrappers, at a cost due to inevitable premature pessimization though.
Your apparent intent is to find the string "PACKAGE TYPE" in the existing list, and then copy the remaining elements in the list to a new list.
If that's the case, then why not do exactly that?
for(QStringList::iterator current_line(inputline.begin()); current_line != inputline.end(); ++current_line){
if(!QString::compare(*current_line,"PACKAGE TYPE"){
list.insert(list.end(), ++current_line, inputline.end());
break;
}
}

How to check if element exists in a linked list in c++?

The problem:
Imagine there is a linked list class which has multiple methods to use. The main part of the code is like this:
int main ()
{
List l;
l.push_back (86);
l.push_front (43);
l.push_front (12);
int intToSearchFor = 12;
if (l.exists (intToSearchFor))
{
cout << "(" << intToSearchFor << ") found :)";
}
else
{
cout << "(" << intToSearchFor << ") not found :(";
}
}
As you can see in this piece of code, the List class has two methods to prepend and append new items to the list. And also it has an iterator method which lets us loop over the items and check the data in each node.
The issue?
I want to create a method which check existence of an element. For example l.exists(12) should return either true or false.
My Solution:
Start to loop over the items with iterator.
Check if the item data is equal to the one you are looking for.
If it is equal then return true. Otherwise if there are more items in the list, move into the next item in the list and go to step 2.
If there are no more items in the list return false.
bool List::exists (int x)
{
Iterator it = this->get_iterator ();
do {
if (it.current->data == x) {
return true;
}
it.current = it.current->next;
} while (it.has_more_elements ());
return false;
}
Full answer:
http://cpp.sh/6cfdh
You should check whether a pointer points to nullptr before accessing data pointed by the pointer (see has_more_elements()). Better naming may avoid some confusion.
while(it.current->data!=x && it.has_more_elements())
it.current=it.current->next;
return (it.current->data==x)?true:false;
If x is not present and it reaches end of list, it.current->data will cause run time error as it may be NULL.
while(it.has_more_elements() && it.current->data!=x)
it.current = it.current->next;
return it.current!=NULL;

Sort and insert in C++

I've got a problem in sorting. I have 2 functions. The first one insert a number into a sorted list and the second one takes in an unsorted list, named unsorted, creates a new list, and repeatedly calls the first one until the new list is a sorted version of the unsorted input. Then return the sorted list.
My understanding is the very first new list is an empty list, which is kind of "sorted", and insert every element into it one by one. But my code somehow doesn't work. The first function passed the test, but the second one did not. Here's my code:
void insertInOrder(list<int>& sorted, int number)
{
if (sorted.empty())
{sorted.push_back(number);
else
{
for(list<int>::iterator I = sorted.begin();I!= sorted.end();I++)
{
if (*I <=number)
{
sorted.insert((++I),number);// since I increases another time here
--I;//decrease once back
return;
}
else
{
sorted.insert(I,number);
return;
}
}
}
}
std::list<int> reorder(std::list<int>& unsorted)
{
std::list<int> ordered;
for (list<int>::iterator J = unsorted.begin(); J!=unsorted.end(); J++)
{
insertInOrder(ordered, *J);
}
return ordered;
}
I think you want is that if the value to insert is less than or equal to the current node, then do nothing and continue the loop, else insert and return. This can of course be written as: If the value to insert is larger than the current node in the list, insert it after the current node and exit loop.
So
if (number > *I)
{
sorted.insert(++I, number); // Insert after current node
break; // Exit loop
}

write trie parsing recursive function with node step over

The purpose: This function parses through a string trie following the path that matches an input string of characters. When all the char in the string are parsed, true is returned. I want to step over a char and return if there is still a valid path.
The application: the strings are a location hierarchy for a highway project. So, project 5 has an alignment C, that has an offset of N and a workzone 3; 5CN3. But, sometimes I want to define a string for all child locations for a project task that covers all the locations. So, '0' is all locations; for a half day operation like grade dirt has no workzones - all the so to represent this task is all workzones in the north alignment C; 5CN0. same for if an operation covers the whole project; 5000.
Approaches: I could have used a wildcard '?' function but I want to keep this specific step over for the purpose of abstracting the locations. Maybe '?' is the right approach, but seems to loose some control. Also, this could be written without the for loop and use a position index parameter; maybe that is where this goes wrong - maybe on backtracking.
Code: nodeT is the trie nodes, word is the input string, this function is a bool and returns 1/0 if the string path exists.
bool Lexicon::containsWordHelper(nodeT *w, string word)) //check if prefix can be combined
{
if(word == "") { //base case: all char found
return true;
} else {
for(int i = 0; i < w->alpha.size(); i++) { //Loop through all of the children of the current node
if (w->alpha[i].letter == word[0])
return containsWordHelper(w->alpha[i].next, word.substr(1));
else if (word[0] == '0') //if '0' then step over and continue searching for valid path
containsWordHelper(w->alpha[i].next, word.substr(1)); //removed return here to allow looping through all the possible paths
} //I think it is continuing through after the loop and triggering return false
}
return false; //if char is missing - meaning the exact code is not there
}
The problem is that this returns false when a '0' wildcard is used. What is going wrong here? My knowledge is limited.
I hacked on this problem for awhile and used the 'howboutthis howboutthat' approach, and found that placing the return at the end of the step over statement works.
bool Lexicon::containsWordHelper(nodeT *w, string word, int &time, int &wag, string compare) //check if prefix can be combined
{
if(word == "") { //base case: all letters found
if ((w->begin-wag) <= time && time <= (w->end+wag))
return w->isWord; // case 2: timecard check for high/low date range
else if (time == ConvertDateToEpoch(9999, 01, 01)) return w->isWord; //this is for single code lookup w/o date
} else {
for(int i = 0; i < w->alpha.size(); i++) { //Loop through all of the children of the current node
if (w->alpha[i].letter == word[0])
return containsWordHelper(w->alpha[i].next, word.substr(1), time, wag, compare);
else if (word[0] == 'ž')
if (containsWordHelper(w->alpha[i].next, word.substr(1), time, wag, compare)) return true;
}
}
return false; //if char is missing - meaning the exact code is not there
}
It seems logical that if I only one the path that ends in true to return then I should place the return after the recursion is done and then conditionally pass back only if true. It works and seems logical in retrospect, but my confidence in this is sketchy at best.
I still have the same question. What is/was going wrong?
You could test the result of the latter containsWordHelper call and return true if the result is true, else continue iterating.
Solved: place a return after an if statement containing the recursive call
bool Lexicon::containsWordHelper(nodeT *w, string word)
{
if(word == "") return w->isWord;
else {
for(int i = 0; i < w->alpha.size(); i++) {
if (w->alpha[i].letter == word[0])
return containsWordHelper(w->alpha[i].next, word.substr(1));
else if (word[0] == 'ž')
if (containsWordHelper(w->alpha[i].next, word.substr(1))) return true;
}
}
return false;
}

STL Vector Erase Not Working

Briefly, I am trying to write a routine that reads comma separated values from a file into a stl vector. This works fine. The values in the csv file might also be in double quotes so I have handled this too by trimming them. However, there is one problem where the values between the quotes might also have commas in them which are not to be treated as delimiters.
If I have a file containing the line
"test1","te,st2","test3","test4"
My file routine reads this into a vector as
"test1"
"te
st2"
"test3"
"test4"
I wrote a routine which I just called PostProcessing. This would go through the vector and correct this problem. It would take each element and check of the first value was a quote. If so it would remove it. It would then look for another quote at the end of the string. If it found one it would just remove it and move onto the next item. If it didn't find one, it would keep going through the vector merging all the following items together until it did find the next quote.
However, this works in merging "te and st2" together into element 2 (index 1) but when I try and erase the required element from the vector it must be failing as the resulting vector output is as follows:
test1
test2
st2"
test3
"test4"
Note also the last element has not been processed because I derement the size of the count but as the vector erase has failed the true count hasn't actually changed.
The PostProcessing code is below. What am I doing wrong?
bool MyClass::PostProcessing()
{
bool bRet = false;
int nCount = m_vecFields.size();
for (int x = 0; x < nCount; x++)
{
string sTemp = m_vecFields[x];
if (sTemp[0] == '"')
{
sTemp.erase(0,1);
if (sTemp[sTemp.size()-1] == '"')
{
sTemp.erase(sTemp.size()-1, 1);
m_vecFields[x] = sTemp;
}
else
{
// find next double quote and merge these vector items
int offset = 1;
bool bFound = false;
while (x+offset < nCount && !bFound)
{
sTemp = sTemp + m_vecFields[x+offset];
if (sTemp[sTemp.size()-1] == '"')
{
// found corresponding "
sTemp.erase(sTemp.size()-1,1);
bFound = true;
}
else
{
offset++;
}
}
if (bFound)
{
m_vecFields[x] = sTemp;
// now remove required items from vector
m_vecFields.erase(m_vecFields.begin()+x+1, m_vecFields.begin()+x+offset);
nCount -= offset;
}
}
}
}
return bRet;
}
Edit: I've spotted a couple of issues with the code which I will be correcting but they don't affect the question being asked.
m_vecFields.erase(m_vecFields.begin()+x+1, m_vecFields.begin()+x+offset);
This function takes a semi-closed interval, which means the "end" of the interval to erase should point one-past the last element to erase. In your case, it points to that element. Change the second argument to m_vecFields.begin()+x+offset+1.
x += offset;
Since you've just processed an item and deleted everything up to the next item, you shouldn't skip offset items here. The x++ from the loop will do just fine.