I need find the bad data presented in imported text file. Bad data is the element that is not in this list:
string salesStaff[] = { "Brad", "Janet", "Dr Scott", "Rifraf", "Nell", "Eddie"};
Repeat elements are allowed, only thing is to find elements not in the list above. Blank elements are allowed. Only looking at second last element.
The file imported:
10051251,Mr,Rodney,Shaw,Shaw Meat Packaging Ltd,Eddie,7552.000000,,740.096000,
10001252,Mrs,Christine,Nichols,Scaffolding Ltd,Brad,6723.000000,Eddie:Brad:,672.300000,
10011265,Mr,Alexander,Marshall,Chemicals Ltd,,1768.000000,Eddie:rippa mate!:Brad:,173.264000
10051257,Mr,Oliver,Zanetti,North Side Cakes Ltd,Eddie,6726.000000,Rifraf:Rifraf:,625.518000,
10031264,Mr,Anthony,Presley,Presley Watches Ltd,Rifraf,4795.000000,,479.500000,
10051263,Mrs,Ruby,Owen,Classic Foods Ltd,Eddie,2918.000000,,271.374000,
My current code:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <sstream>
using namespace std;
string ffname = "C:\\Users\\chuboi\\Documents\\ST2Assignment1\\NamesdataA1txtbaddata.txt";
struct TaxPayer {
// Data part
std::string custID{};
std::string custhono{};
std::string custFN{};
std::string custSN{};
std::string custCN{};
std::string custCS{};
float VP{};
std::string custPS{};
float VC{};
// Extractor
friend std::istream& operator >> (std::istream& is, TaxPayer& tp) {
// Read a complete line
std::string line{};
if (std::getline(is, line))
{
if (not line.empty())
{
// Put it into a stringstream for further extraction
std::istringstream iss{ line };
// Now, extract the data parts
std::getline(iss, tp.custID, ',');
std::getline(iss, tp.custhono, ',');
std::getline(iss, tp.custFN, ',');
std::getline(iss, tp.custSN, ',');
std::getline(iss, tp.custCN, ',');
std::getline(iss, tp.custCS, ',');
// Read and convert
std::getline(iss, line, ',');
tp.VP = std::stof(line);
std::getline(iss, tp.custPS, ',');
std::getline(iss, line, ',');
tp.VC = std::stof(line);
}
}
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const TaxPayer& tp) {
return os << tp.custID << ' ' << tp.custhono << ' ' << tp.custFN << ' ' << tp.custSN
<< ' ' << tp.custSN << ' ' << tp.custCN << ' ' << tp.custCS
<< ' ' << tp.VP << ' ' << tp.custPS << ' ' << tp.VC << '\n';
}
};
struct TaxPayers {
// Data
std::vector<TaxPayer> taxPayers{};
string showinfo(size_t i) {
string info = taxPayers[i].custID " " taxPayers[i].custhono " "
taxPayers[i].custFN " " taxPayers[i].custSN " " taxPayers[i].custCN;
return info;
}
string salesstaff(size_t i) {
string prestaff = taxPayers[i].custPS;
return prestaff;
}
// Extractor
friend std::istream& operator >> (std::istream& is, TaxPayers& tp) {
// clar old data
tp.taxPayers.clear();
// Read all new existing data and store in vector
TaxPayer taxPayer{};
while (is >> taxPayer)
tp.taxPayers.push_back(taxPayer);
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const TaxPayers& tp) {
for (const TaxPayer& taxPayer : tp.taxPayers)
os << taxPayer;
return os;
}
};
void opt_A()
{
std::ifstream sourceFile(ffname);
if (!sourceFile.is_open())
{
cout << "No file found, please check for files again" << endl;
return;
}
string salesStaff[] = { "Brad", "Janet", "Dr Scott", "Rifraf", "Nell", "Eddie" };
TaxPayers taxPayers{};
sourceFile >> taxPayers;
int x = 1;
for (size_t i = 0; i < taxPayers.taxPayers.size(); i)
{
if (taxPayers.salesstaff(i) != salesStaff[6])
{
cout << "Audit Report" << endl;
cout << "-------------------" << endl;
cout << "File: " << ffname << endl;
cout << "Account Details : " << taxPayers.showinfo(i) << endl;
cout << "Details : " << taxPayers.salesstaff(i) << "\n\n";
cout << "Total count of bad data found: " << (x) << "\n\n";
x ;
}
}
}
int main()
{
opt_A();
}
The current output is:
Audit Report
-------------------
File: C:\Users\chuboi\Documents\ST2Assignment1\NamesdataA1txtbaddata.txt
Account Details : 10001252 Mrs Christine Nichols Nichols Scaffolding Ltd
Details : Eddie:Brad:
Total count of bad data found: 1
Audit Report
-------------------
File: C:\Users\chuboi\Documents\ST2Assignment1\NamesdataA1txtbaddata.txt
Account Details : 10011265 Mr Alexander Marshall Marshall Chemicals Ltd
Details : Eddie:rippa mate!:Brad:
Total count of bad data found: 2
Audit Report
-------------------
File: C:\Users\chuboi\Documents\ST2Assignment1\NamesdataA1txtbaddata.txt
Account Details : 10051257 Mr Oliver Zanetti North Side Cakes Ltd
Details : Rifraf:Rifraf:
Total count of bad data found: 3
While I need it to be:
Audit Report
-------------------
File: C:\Users\chuboi\Documents\ST2Assignment1\NamesdataA1txtbaddata.txt
Account Details : 10011265 Mr Alexander Marshall Marshall Chemicals Ltd
Details : Eddie:rippa mate!:Brad:
Total count of bad data found: 1
Thank you for the help in advance.
CodePudding user response:
You have a more complex comparison than you are doing. You have two primary conditions:
- Is
taxPayers.salesstaff(i)
empty? (if so, you are done); or - Does each of the
taxPayers.salesstaff(i)
components, e.g.staff1:staff2:...
appear in thesalesStaff[]
array?
It is this second condition that is a many-to-many relationship that has many subconditions. In order to make this determination, you must separate the taxPayers.salesstaff(i)
entry on ':'
(much like you did input from your data file on ','
). Then you must loop over each entry and compare the entry against each in the salesStaff[]
array. If ONE of the entries in taxPayers.salesstaff(i)
does not match ANY of the entries in the salesStaff[]
array. then you have a bad entry.
You can use a couple of bool
flags to help you work through the checks. One way to do that is:
void opt_A()
{
std::ifstream sourceFile(ffname);
if (!sourceFile.is_open())
{
cout << "No file found, please check for files again" << endl;
return;
}
string salesStaff[] = { "Brad", "Janet", "Dr Scott",
"Rifraf", "Nell", "Eddie" };
size_t nsstaff = sizeof salesStaff / sizeof *salesStaff;
TaxPayers taxPayers{};
sourceFile >> taxPayers;
int x = 0;
/* output list heading before loop */
cout << "Audit Report" << '\n' <<
"-------------------" << '\n' <<
"File: " << ffname << "\n\n";
/* loop over each taxpayer */
for (size_t i = 0; i < taxPayers.taxPayers.size(); i)
{
bool nomatch = false; /* flag, no match for non-empty entry */
/* only check salesstaff if not empty */
if (!taxPayers.salesstaff(i).empty())
{
/* instringstream to split taxPayers.salesstaff on ':' */
istringstream iss {taxPayers.salesstaff(i)};
std::string staff{}; /* temporary for each taxpayer staff */
/* loop over each taxpayer.salesstaff staff1:staff2:... entry */
while (getline (iss, staff, ':'))
{
bool matched = false; /* is entry matched in salesStaff[] */
/* loop over each valid salesStaff */
for (size_t j = 0; j < nsstaff; j )
{
/* if staff matches valid salesStaff */
if (staff == salesStaff[j]) {
matched = true; /* set found flag true */
break;
}
}
/* after looping over all, check if no match found */
if (!matched)
{
nomatch = true; /* set nomatch flag */
}
}
}
if (nomatch) /* only print details if no match for salesstaff enty */
{
cout << "Account Details : " << taxPayers.showinfo(i) << '\n' <<
"Details : " << taxPayers.salesstaff(i) << "\n\n";
x ;
}
}
/* output summary after loop */
cout << "Total count of bad data found: " << (x) << "\n\n";
}
(note: above the heading and summary data go outside the loop unless you want that printed for each bad record -- which doesn't seem correct given the summary line)
Also note, there are many more ways you can do this. You can reduce the number of loops and avoid splitting taxPayers.salesstaff(i)
by looping over each in the salesStaff[]
array and using .substr()
to determine if that staff occurs as one of the parts of taxPayers.salesstaff(i)
. How you want to do it is up to you.
Also note, as I explained in your last question, you need to validate each input.
Example Use/Output
With your data in my file dat/taxpayers.txt
, running the program you would get:
$ ./bin/taxpayercheck
Audit Report
-------------------
File: dat/taxpayers.txt
Account Details : 10011265 Mr Alexander Marshall Chemicals Ltd
Details : Eddie:rippa mate!:Brad:
Total count of bad data found: 1
Let me know if you have further questions.