split a set of data into different category - c++

I have a .txt file which is a set of data (2000 lines) example shown below
Time,Price ($),Volume,Value ($),Condition
10/10/2013 04:57:27 PM,5.81,5000,29050.00,LT XT
10/10/2013 04:48:05 PM,5.81,62728,364449.68,SX XT
10/10/2013 04:10:33 PM,5.81,451,2620.31,
10/10/2013 04:10:33 PM,5.81,5000,29050.00,
How do i split them into chunks of each category? Example:
Volume - (whole data of volume)
Price - (whole data of price)
I understand that need to use delimiter to split but i don't know how to go about it (would need a little push on codings).
I'm using vectors to store these set of data by line.
Any help will be appreciated. Thanks
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<sstream>
//#include "Header.h"
using namespace std;
int main()
{
//open file
ifstream inFile("Course_of_sale.txt", ifstream::in);
// if can read
if (inFile.good())
{
std::vector<string> strVector;
//create vector
string line;
//read and push to back
while (getline(inFile, line))
{
getline(inFile, line);
strVector.push_back(line);
}
vector<string>::iterator it;
for (it = strVector.begin(); it < strVector.end(); it++)
{
cout << *it << endl;
}
stringstream ss(line);
string field;
while (getline(ss, field, ','))
{
getline(inFile, line);
strVector.push_back(line);
}
cout << "\nSize : " << strVector.capacity() << " elements \n";
}
system("Pause");
Currently only managed to do a read from file.(and this code is copied from SO)

This was my attempt.
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
struct entry {
int time;
double price;
int volume;
double value;
std::string condition;
entry(const int ti, const double pr, const int vo, const double va, const std::string &co):
time{ ti }, price{ pr }, volume{ vo }, value{ va }, condition{ co }
{ }
};
std::vector<std::string> &split(const std::string &str, const char delim, std::vector<std::string> &ret) {
std::stringstream ss(str);
std::string tmp;
while (std::getline(ss, tmp, delim))
ret.push_back(tmp);
return ret;
}
int main(int argc, char **argv) {
std::vector<entry> vec;
std::ifstream file("test.txt");
std::string line;
std::vector<std::string> str;
while (std::getline(file, line)) {
std::vector<std::string>().swap(str);
split(line, ',', str);
std::string tmp{ "" };
if (str.size() > 4)
std::string tmp(str.at(4));
entry e(
std::stoi(str.at(0)),
std::stod(str.at(1)),
std::stoi(str.at(2)),
std::stod(str.at(3)),
tmp
);
vec.push_back(e);
}
system("pause");
return 0;
}
It's only fault tolerant if you leave off the condition.

Related

How can I compare the third token from each line using 'getline()'?

Input file: In each row, there's an entry that is a pair of ID - name - GPA. Values are tab-delimited.
20210001 Bill 3.61
20210002 Joe 3.21
20210003 Royce 4.32
20210004 Lucy 2.21
I have to rearrange this file sorted by the GPA (in decreasing order).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
if (inputfile.is_open()) {
string line;
while (getline(inputfile, line)) {
string token;
stringstream ss(line);
while (getline(ss, token, '\t')) {
}
}
}
inputfile.close();
outputfile.close();
return 0;
}
I'm not sure what to do next.
When doing I/O from/to streams (like file streams) it usually makes it easier to create a class to keep the data for each record in the file and to create overloads for operator>> (in) and operator<< (out).
Example:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// one line in the file could possibly have this representation in your program:
struct record {
std::uint32_t ID;
std::string name;
double GPA;
};
// an overload to read one line of data from an istream (like an ifstream) using getline
std::istream& operator>>(std::istream& is, record& r) {
if(std::string line; std::getline(is, line)) {
std::istringstream iss(line);
if(not (iss >> r.ID >> r.name>> r.GPA)) {
is.setstate(std::ios::failbit);
}
}
return is;
}
// an overload to write one line to an ostream (like an ofstream)
std::ostream& operator<<(std::ostream& os, const record& r) {
return os << r.ID<< '\t' << r.name << '\t' << r.GPA << '\n';
}
With that boilerplate in place, making the actual program becomes easy.
int main() {
std::ifstream inputfile("input.txt");
// read all records from the file into a vector
std::vector<record> records(
std::istream_iterator<record>(inputfile),
std::istream_iterator<record>{}
);
// sort the records according to GPA
// if you want a decending order, just make it return rhs.GPA < lhs.GPA;
std::sort(records.begin(), records.end(),
[](const record& lhs, const record& rhs) {
return lhs.GPA < rhs.GPA;
}
);
std::ofstream outputfile("output.txt");
// put the result in the output file
std::copy(records.begin(),
records.end(),
std::ostream_iterator<record>(outputfile));
}
There may be a few things in this answer that you haven't seen before. I'll list resources for those I anticipate may require some reading:
operator<< / operator>> overloading. See Stream extraction and insertion
std::istringstream - You put a std::string in it - and then it behaves like any other std::istream (like a std::ifstream).
std::istream_iterator/std::ostream_iterator
std::sort / std::copy are two of the many algorithms in the standard library.
std::vector - A class template acting as a dynamic array where you can add and remove data, like record in this answer.
Lambda expressions - In this answer it's the functor [](const record& lhs, const record& rhs) { ... } used to sort the records.
If you know exactly how many tokens are in a line:
You could simply getline() 3 times with the tab delimiter, and store the values separately.
string id;
string name;
string gpa;
getline(ss, id, '\t');
getline(ss, name, '\t');
getline(ss, gpa, '\t');
This logic would live within your loop that iterates over the lines in the file.
You could use a struct to contain all your fields:
struct user
{
int id; string name; double point;
};
Then insert all of them into a std::vector and finally use sort() with the comp parameter to sort by points.
Code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;
struct user
{
int id; string name; double point;
};
vector<user> users;
void stripInfoFromString(string inp)
{
stringstream cur(inp);
user curUser;
cur >> curUser.id >> curUser.name >> curUser.point;
users.push_back(curUser);
}
bool compareUser(user x, user y)
{
return x.point < y.point;
}
int main()
{
string a1 = "20210001 Bill 3.61";
string a2 = "20210002 Joe 3.21";
string a3 = "20210003 Royce 4.32";
string a4 = "20210004 Lucy 2.21";
stripInfoFromString(a1);
stripInfoFromString(a2);
stripInfoFromString(a3);
stripInfoFromString(a4);
sort(users.begin(), users.end(), compareUser);
cout << fixed << setprecision(2);
for (user cur : users)
{
cout << cur.id << " " << cur.name << " " << cur.point << "\n";
}
}
Output:
20210004 Lucy 2.21
20210002 Joe 3.21
20210001 Bill 3.61
20210003 Royce 4.32
I used standard input/output to minimize the code, you can simply switch for file inputs easily.
More info:
struct : https://en.cppreference.com/w/c/language/struct
sort() : https://en.cppreference.com/w/cpp/algorithm/sort
Also, see here why is using namespace std; considered bad practice.
I would suggest defining a struct to hold the 3 tokens, and then create a std::vector holding instances of that struct for each line. You can then sort that vector on the 3rd token. You already have <vector> in your header includes.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct entry
{
int id;
string name;
double gpa;
};
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
vector<entry> entries;
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
string line;
while (getline(inputfile, line)) {
istringstream iss(line);
entry e;
string token;
getline(iss, token, '\t');
e.id = stoi(token);
getline(iss, e.name, '\t');
getline(iss, token, '\t');
e.gpa = stod(token);
/* alternatively:
iss >> e.id >> e.name >> e.gpa;
*/
entries.push_back(e);
}
inputfile.close();
outputfile.close();
sort(entries.begin(), entries.end(),
[](const entry &e1, const entry &e2){
return e1.gpa > e2.gpa;
}
);
for (const entry &e : entries) {
outputfile << e.id << '\t' << e.name << '\t' << e.gpa << '\n';
}
return 0;
}
Demo

Vectors in C++ Files

Within this function, I am passing multiple files. It was implemented with arrays before, and now I need to convert all of the arrays to vectors. The issue I have is when I read in from the files, it does not stop. Why??
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice, vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size() << endl;
}
readIn(appIn, appName, appPrice, appquantity);
readIn(drinkIn, drinkName, drinkPrice, driquantity);
readIn(entreeIn, entreeName, entreePrice, entquantity);
readIn(dessertIn, desName, desPrice, dessquantity);
This is the function and calls. Not sure why when outputting the item name, item price and quantity sizes, it just continually reads in values.
Expanding your code to an executable example:
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size()
<< endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}
Given ...
$ cat data_adamp.txt
animal a 1 2
beach b 3 4
cart c 4 5
dog d 6 7
... compiling with (GCC version 6.4.0):
$ gcc adamp.cpp -lstdc++ -oadamp
... lets me run:
$ ./adamp
... which does indeed never stop.
One way to solve this problem is to tokenize each line and convert the two rightmost fields to doubles and the rest to the record name, e.g. (using the approach in the highest-ranked answer to How do I iterate over the words of a string?):
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
using namespace std;
// See the highest-scoring answer to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string/236803#236803
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
string nTemp;
double pTemp;
int qTemp;
string line;
while(getline(iFile,line))
{
char delim = ' ';
vector<string> s = split(line,delim);
istringstream ss;
ss.str(s.back());
ss >> qTemp;
s.pop_back();
ss.str(s.back());
ss.clear();
ss >> pTemp;
s.pop_back();
nTemp = "";
for (int i = 0; i < s.size(); i++)
{
if (i > 0) nTemp.append(" ");
nTemp.append(s[i]);
}
itemName.push_back(nTemp);
itemPrice.push_back(pTemp);
quantity.push_back(qTemp);
cout << nTemp << "++" << pTemp << "++" << qTemp << endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}

extract individual words from string c++

I am trying to make a C++ program that receives user input, and extracts the individual words in the string, e.g. "Hello to Bob" would get "Hello", "to", "Bob". Eventually, I will be pushing these into a string vector. This is the format I tried to use when designing the code:
//string libraries and all other appropriate libraries have been included above here
string UserInput;
getline(cin,UserInput)
vector<string> words;
string temp=UserInput;
string pushBackVar;//this will eventually be used to pushback words into a vector
for (int i=0;i<UserInput.length();i++)
{
if(UserInput[i]==32)
{
pushBackVar=temp.erase(i,UserInput.length()-i);
//something like words.pushback(pushBackVar) will go here;
}
}
However, this only works for the first space encountered in the string.It does not work if there are any spaces before the word (e.g. if we have "Hello my World", pushBackVar will be "Hello" after the first loop, and then "Hello my" after the second loop, when I want "Hello" and "my".) How do I fix this? Is there any other better way to extract individual words from a string? I hope I haven't confused anyone.
See Split a string in C++?
#include <string>
#include <sstream>
#include <vector>
using namespace std;
void split(const string &s, char delim, vector<string> &elems) {
stringstream ss(s);
string item;
while (getline(ss, item, delim)) {
elems.push_back(item);
}
}
vector<string> split(const string &s, char delim) {
vector<string> elems;
split(s, delim, elems);
return elems;
}
So in your case just do:
words = split(temp,' ');
You can use the operator >> direct to a microbuffer (string) to extract the word. (getline is not needed). Take a look at the function below:
vector<string> Extract(const string& Text) {
vector<string> Words;
stringstream ss(Text);
string Buf;
while (ss >> Buf)
Words.push_back(Buf);
return Words;
}
#include <algorithm> // std::(copy)
#include <iostream> // std::(cin, cout)
#include <iterator> // std::(istream_iterator, back_inserter)
#include <sstream> // std::(istringstream)
#include <string> // std::(string)
#include <vector> // std::(vector)
using namespace std;
auto main()
-> int
{
string user_input;
getline( cin, user_input );
vector<string> words;
{
istringstream input_as_stream( user_input );
copy(
istream_iterator<string>( input_as_stream ),
istream_iterator<string>(),
back_inserter( words )
);
}
for( string const& word : words )
{
cout << word << '\n';
}
}
Here I have created a vector of words from the sentence.
#include<bits/stdc++.h>
using namespace std;
int main(){
string s = "the devil in the s";
string word;
vector<string> v;
for(int i=0; i<s.length(); i++){
if(s[i]!=' '){
word+=s[i];
}
else{
v.push_back(word);
if(i<s.length()+1)
word.clear();
}
}
v.push_back(word);
for(auto i:v){
cout<<i<<endl;
}
}

C++ reading from data from text file

I have the following data:
$GPVTG,,T,,M,0.00,N,0.0,K,A*13
I need to read the data, however there are blanks in between the commas, therefore I am not sure how I should read the data.
Also, how do I select GPVTG only for a group of data? For example:
GPVTG,,T,,M
GPGGA,184945.00
GPRMC,18494
GPVTG,,T,,M,0
GPGGA,184946.000,3409
I have tried using:
/* read data line */
fgets(gpsString,100,gpsHandle);
char type[10] = "GPVTG";
sscanf(gpsString," %GPVTG", &type);
if (strcmp(gpsString, "GPTVG") == 0){
printf("%s\n",gpsString);
}
Thats what i'd do
#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
vector<string> &split(const string &s, char delim, vector<string> &elems) {
stringstream ss(s);
string item;
while (getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
vector<string> split(const string &s, char delim) {
vector<string> elems;
split(s, delim, elems);
return elems;
}
int main()
{
ifstream ifs("file.txt");
string data_string;
while ( getline( ifs, data_string ) )
{
//i think you'd want to erase first $ charachter
if ( !data_string.empty() ) data_string.erase( data_string.begin() );
//now all data put into array:
vector<string> data_array = split ( data_string, ',' );
if ( data_array[0] == "GPVTG" )
{
//do whatever you want with that data entry
cout << data_string;
}
}
return 0;
}
Should handle your task. All empty elements will be empty "" strings in array. Ask if you need anything else.
Credits for split functions belong to Split a string in C++? answer.
How about this
#include <istream>
#include <sstream>
class CSVInputStream {
public:
CSVInputStream(std::istream& ist) : input(ist) {}
std::istream& input;
};
CSVInputStream& operator>>(CSVInputStream& in, std::string& target) {
if (!in.input) return in;
std::getline(in.input, target , ',');
return in;
}
template <typename T>
CSVInputStream& operator>>(CSVInputStream& in, T& target) {
if (!in.input) return in;
std::string line;
std::getline(in.input, line , ',');
std::stringstream translator;
translator << line;
translator >> target;
return in;
}
//--------------------------------------------------------------------
// Usage follow, perhaps in another file
//--------------------------------------------------------------------
#include <fstream>
#include <iostream>
int main() {
std::ifstream file;
file.open("testcsv.csv");
CSVInputStream input(file);
std::string sentence_type;
double track_made_good;
char code;
double unused;
double speed_kph;
char speed_unit_kph;
double speed_kmh;
char speed_unit_kmh;
input >> sentence_type >> track_made_good >> code;
input >> unused >> unused;
input >> speed_kph >> speed_unit_kph;
input >> speed_kmh >> speed_unit_kmh;
std::cout << sentence_type << " - " << track_made_good << " - ";
std::cout << speed_kmh << " " << speed_unit_kmh << " - ";
std::cout << speed_kph << " " << speed_unit_kph << std::endl;;
}
This separates the comma separation from the reading of the values, and can be reused on
most other comma separated stuff.
If you want use C++ style code based on fstream:
fin.open(input);
cout << "readed";
string str;
getline(fin, str); // read one line per time

Scanning information from file in c++

I have a file with the following information:
INTERSECTIONS:
1 0.3 mountain and 1st
2 0.9 mountain and 2nd
3 0.1 mountain and 3rd
How do I scan in c++ so that it scans the first number and stores it in an int, then scans the next number and stores it separately, then stores the name of the streets in an a string? I just switched from c so I know how to do it in C just by using
fscanf("%d %lf %s", int, float, string);
or
fgets
with strings but don't know how to do this in C++. Any help would be appreciated
main:
#include<iostream>
#include<list>
#include <fstream>
#include<cmath>
#include <cstdlib>
#include <string>
#include "vertex.h"
#include "edge.h"
#include "global.h"
using namespace std;
int main ( int argc, char *argv[] ){
if(argc != 4){
cout<< "usage: "<< argv[0]<<"<filename>\n";
}
else{
ifstream map_file (argv[3]);
if(!map_file.is_open()){
cout<<"could not open file\n";
}
else{
std::string line;
std::ifstream input(argv[3]);
int xsect;
int safety;
std:string xname;
std::list<vertex> xsection;
std::list<edge> EdgeList;
while (std::getline(input, line))
{
std::istringstream iss(line);
iss >> xsect >> safety;
std::getline(iss, xname);
}
}
}
}
It's enough with std::getline and std::istringstream and the standard C++ stream input operator:
std::string line;
std::ifstream input(...);
while (std::getline(input, line))
{
std::istringstream iss(line);
int v1;
double v2;
std::string v3;
iss >> v1 >> v2;
std::getline(iss, v3);
}