Reputation: 5
nm92,Nate,Matthews,Aetna,1
sc91,Steve,Combs,Cigna,2
ml94,Morgan,Lands,BCBS,3
kb93,Kyle,Borris,Aetna,2
I am trying to take a CSV input file like above, store it, sort it by insurance (col 4), and then write it to diff files based on insurance but in alphabetical order by last name.
So in this program, I have a vector of uniqueInsurances, which in turn have a vector of enrollees. It is this vector of enrollees that I want to sort alphabetically by last name (col 3), so that if uniqueInsurances[0].name is Aetna, then uniqueInsurances[0].enrollees[] will have Kyle Borris listed BEFORE Nate Matthews. Right now I have it stored the other way with Nate Matthews listed before Kyle Borris.
I think it's due to the vector of vectors and nested for loops required for this problem that's getting me mixed up, so I was wondering if someone could help guide me in terms of the best way to sort the enrollee vectors for each uniqueInsurance?
struct enrollee
{
string userid = "";
string fname = "";
string lname = "";
string insurance = "";
string version = "";
};
struct uniqueInsurance
{
string name = "";
int numEnrollees = 0;
vector <enrollee> enrollVector;
};
Upvotes: 0
Views: 634
Reputation: 15277
This is a follow up of your question yesterday:
I modified my code and added one line for sorting.
Please see:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <regex>
struct Enrollee
{
// Data
std::string userid{};
std::string fname{};
std::string lname{};
std::string insurance{};
std::string version{};
// Overload Extractor Operator to read data from somewhere
friend std::istream& operator >> (std::istream &is, Enrollee& e) {
std::vector<std::string> wordsInLine{}; // Here we will store all words that we read in onle line;
std::string wholeLine; // Temporary storage for the complete line that we will get by getline
std::regex separator("[ \\;\\,]"); ; // Separator for a CSV file
std::getline(is, wholeLine); // Read one complete line and split it into parts
std::copy(std::sregex_token_iterator(wholeLine.begin(), wholeLine.end(), separator, -1), std::sregex_token_iterator(), std::back_inserter(wordsInLine));
// If we have read all expted strings, then store them in our struct
if (wordsInLine.size() == 5) {
e.userid = wordsInLine[0];
e.fname = wordsInLine[1];
e.lname = wordsInLine[2];
e.insurance = wordsInLine[3];
e.version = wordsInLine[4];
}
return is;
}
// Overload Inserter operator. Insert data into output stream
friend std::ostream& operator << (std::ostream& os, const Enrollee& e) {
return os << "userid is: " << e.userid << "\nfname is: " << e.fname << "\nlname is: " << e.lname << "\ninsurance is: " << e.insurance << "\nversion is: " << e.version << '\n';
}
};
int main()
{
// Her we will store all Enrollee data in a dynamic growing vector
std::vector<Enrollee> enrollmentData{};
// Define inputFileStream and open the csv
std::ifstream inputFileStream("r:\\input.csv");
// If we could open the file
if (inputFileStream)
{
// Then read all csv data
std::copy(std::istream_iterator<Enrollee>(inputFileStream), std::istream_iterator<Enrollee>(), std::back_inserter(enrollmentData));
// Sort the data
std:sort(enrollmentData.begin(),enrollmentData.end(),[](const Enrollee& left, const Enrollee& right){return left.lname < right.lname;});
// For Debug Purposes: Print all data to cout
std::copy(enrollmentData.begin(), enrollmentData.end(), std::ostream_iterator<Enrollee>(std::cout, "\n"));
}
else {
std::cerr << "Could not open file 'input.csv'\n";
}
}
Upvotes: 0
Reputation: 44258
If your task is just to write to different files sorted names then you do not need the second structure. Just have one std::vector<enrollee>
sort it based on insurance and names, then iterate over it. When insurance name changes reopen file accordingly:
std::vector<enrollee> enrollees;
// read them from csv file
std::sort( enrollees.begin(), enrollees.end(), []( const enrollee &e1, const enrollee &e2 ) {
return std::tie( e1.insurance, e1.fname, e1.lname ) < std::tie( e2.insurance, e2.fname, e2.lname );
} );
std::string insurance;
std::ofstream out;
for( const auto &e : enrollees ) {
if( insurance != e.insurance ) {
insurance = e.insurance;
out.open( insurance + ".csv" );
}
out << e.fname << ',' << e.lname << std::endl;
}
This sorts by first name then last name, if you need last name first just swap their order in std::tie()
Upvotes: 1