Here I have an excel file whose first column has ID's i.e:
ID
12
32
45
12
..
There are other columns as well but I only want to read the data present in first column i.e. ID.
Here is my code which throws exception. I don't know why?
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include<string>
#include<cstdlib>
//std::find
#include<cstring>
using namespace std;
int main()
{
ifstream fin("1.csv");
string line;
int rowCount = 0;
int rowIdx = 0; //keep track of inserted rows
//count the total nb of lines in your file
while (getline(fin, line)) {
rowCount++;
}
//this will be your table. A row is represented by data[row_number].
//If you want to access the name of the column #47, you would
//cout << data[0][46]. 0 being the first row(assuming headers)
//and 46 is the 47 column.
//But first you have to input the data. See below.
std::vector<std::vector<std::string>> data;
fin.clear(); //remove failbit (ie: continue using fin.)
fin.seekg(fin.beg); //rewind stream to start
while (getline(fin, line)) //for every line in input file
{
stringstream ss(line); //copy line to stringstream
string value;
while (getline(ss, value, ',')) { //for every value in that stream (ie: every cell on that row)
data[rowIdx].push_back(value);//add that value at the end of the current row in our table
}
rowIdx++; //increment row number before reading in next line
}
fin.close();
//Now you can choose to access the data however you like.
//If you want to printout only column 47...
int colNum;
string colName = "ID";
//1.Find the index of column name "computer science" on the first row, using iterator
//note: if "it == data[0].end()", it means that that column name was not found
vector<string>::iterator it = find(data[0].begin(), data[0].end(), colName);
//calulate its index (ie: column number integer)
colNum = std::distance(data[0].begin(), it);
//2. Print the column with the header "computer science"
for (int row = 0; row < rowCount; row++)
{
cout << data[row][colNum] << "\t"; //print every value in column 47 only
}
cout << endl;
return 0;
}
Kindly help me to fix the issue. I want to display only first column which contain ID's.
Here's a simplified version of the above code. It gets rid of the 2D vector, and only reads the first column.
std::vector<std::string> data;
ifstream fin("1.csv");
string line;
while (getline(fin, line)) //for every line in input file
{
stringstream ss(line); //copy line to stringstream
string value;
if (getline(ss, value, ',')) {
data.push_back(value);
}
}
EDIT
How to display the data
for (size_t i = 0; i < data.size(); ++i)
cout << data[i] << '\n';
The problem:
std::vector<std::vector<std::string>> data;
Allocates a vector of vectors. Both dimensions are currently set to 0.
data[rowIdx].push_back(value);
pushes into and potentially resizes the inner vector, but the outer vector remains size 0. No value of rowIdx is valid. The naive solution is to use rowCount to size the outer vector, but it turns out that's a waste. You can assemble whole rows and then push_back the row into data, but even this is a waste since only one column is needed.
One of the beauties of vector is you don't have to know the number of rows. Your make a row vector, push the columns into it, then push the row into data. when you hit the end of he file, you're done reading. No need to read the file twice, but you probably trade off a bit of wasted storage on data's last self-resize.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
// reduced includes to minimum needed for this example
// removed using namespace std; to reduce odds of a naming collision
int main() {
std::ifstream fin("1.csv"); // Relative path, so watch out for problems
// with working directory
std::string line;
std::vector<std::string> data; // only need one column? Only need one
// dimension
if (fin.is_open())
{
while (std::getline(fin, line)) //for every line in input file
{
std::stringstream ss(line);
std::string value;
if (std::getline(ss, value, ','))
{
// only take the first column If you need, say, the third
// column read and discard the first two columns
// and store the third
data.push_back(value); // vector sizes itself with push_back,
// so there is no need to count the rows
}
}
}
else
{
std::cerr << "Cannot open file\n";
return -1;
}
// use the column of data here
}
Related
Hi all, im just start to learn how to do the csv file management using c++, currently this code works. it can print out the 'math' column.
but that is only if when i assigned every column using the getline(ss,#any column variable#, ',')
then i print out the column that i want. but if im using this for a big list, lets say a csv file that have about 100 column. then, how can i simplified it? or is there any ways for me to only get specific column only without assigning/parsing each column to each variable? lets say from 100 column, i only want the column 47 with any possible names? or maybe i could get the column by its name?
Thanks.
or is there any ways for me to only get specific column only without assigning/parsing each column to each variable?
It's not really practical with the CSV format to avoid reading every column, so really what you want to do is basically just discard the columns you do not want, much like you are already doing.
To make it work with an unknown number of columns, you can read into a std::vector, which is basically a dynamically sized array, so really useful for cases like this.
std::vector<std::string> read_csv_line(const std::string &line)
{
std::vector<std::string> ret;
std::string val;
std::stringstream ss(line);
while (std::getline(ss, val, ','))
ret.push_back(std::move(val));
return ret;
}
...
std::getline(is, line);
auto row = read_csv_line(line);
if (row.size() > 10) // Check each row is expected size!
std::cout << row[0] << ", " << row[10] << std::endl;
else std::cerr << "Row too short" << std::endl;
You can then access the specific columns you want.
or maybe i could get the column by its name?
Assuming your CSV file has a header line, you can read that into say a std::unordered_map<std::string, size_t> where the value is the column index. Alternatively something like a std::vector with std::find.
Note that handling of quoted values, and some other possible CSV features can't be done with a single std::getline.
Here's a quick [working] example.
The 1st part reads in the table.
The 2nd part (after fin.close()) lets you choose what you want to print out (or whatever you choose to do with it).
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm> //std::find
using namespace std;
int main(int argc, char** argv)
{
ifstream fin("filename");
string line;
int rowCount=0;
int rowIdx=0; //keep track of inserted rows
//count the total nb of lines in your file
while(getline(fin,line)){
rowCount++;
}
//this will be your table. A row is represented by data[row_number].
//If you want to access the name of the column #47, you would
//cout << data[0][46]. 0 being the first row(assuming headers)
//and 46 is the 47 column.
//But first you have to input the data. See below.
vector<string> data[rowCount];
fin.clear(); //remove failbit (ie: continue using fin.)
fin.seekg(fin.beg); //rewind stream to start
while(getline(fin,line)) //for every line in input file
{
stringstream ss(line); //copy line to stringstream
string value;
while(getline(ss,value,’,’)){ //for every value in that stream (ie: every cell on that row)
data[rowIdx].push_back(value);//add that value at the end of the current row in our table
}
rowIdx++; //increment row number before reading in next line
}
}
fin.close();
//Now you can choose to access the data however you like.
//If you want to printout only column 47...
int colNum=47; //set this number to the column you want to printout
for(int row=0; row<rowCount; row++)
{
cout << data[row][colNum] << "\t"; //print every value in column 47 only
}
cout << endl
return 0;
}
EDIT: Adding this for a more complete answer.
To search a column by name, replace the last for loop with this snippet
//if you want to look up a column by name, instead of by column number...
//Use find on that row to get its column number.
//Than you can printout just that column.
int colNum;
string colName = "computer science";
//1.Find the index of column name "computer science" on the first row, using iterator
//note: if "it == data[0].end()", it means that that column name was not found
vector<string>::iterator it = find(data[0].begin(), data[0].end(),colName);
//calulate its index (ie: column number integer)
colNum = std::distance(data[0].begin(), it);
//2. Print the column with the header "computer science"
for(int row=0; row<rowCount; row++)
{
cout << data[row][colNum] << "\t"; //print every value in column 47 only
}
cout << endl
return 0;
}
I am trying to read a database file (as txt) where I want to skip empty lines and skip the column header line within the file and store each record as an array. I would like to take stop_id and find the stop_name appropriately. i.e.
If i say give me stop 17, the program will get "Jackson & Kolmar".
The file format is as follows:
17,17,"Jackson & Kolmar","Jackson & Kolmar, Eastbound, Southeast Corner",41.87685748,-87.73934698,0,,1
18,18,"Jackson & Kilbourn","Jackson & Kilbourn, Eastbound, Southeast Corner",41.87688572,-87.73761421,0,,1
19,19,"Jackson & Kostner","Jackson & Kostner, Eastbound, Southeast Corner",41.87691497,-87.73515882,0,,1
So far I am able to get the stop_id values but now I want to get the stop name values and am fairly new to c++ string manipulation
mycode.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string filename;
filename = "test.txt";
string data;
ifstream infile(filename.c_str());
while(!infile.eof())
{
getline(infile,line);
int comma = line.find(",");
data = line.substr(0,comma);
cout << "Line " << count << " "<< "is "<< data << endl;
count++;
}
infile.close();
string sent = "i,am,the,champion";
return 0;
}
You can use string::find 3 times to search for the third occurrence of the comma, and you must store the positions of the last 2 occurrences found in line, then use them as input data with string::substr and get the searched text:
std::string line ("17,17,\"Jackson & Kolmar\",\"Jackson & Kolmar, Eastbound, Southeast Corner\",41.87685748,-87.73934698,0,,1");
std::size_t found=0, foundBack;
int i;
for(i=0;i<3 && found!=std::string::npos;i++){
foundBack = found;
found=line.find(",",found+1);
}
std::cout << line.substr(foundBack+1,found-foundBack-1) << std::endl;
You can read the whole line of the file intoa string and then use stringstream to give you each piece one at a time up until and exluding the commas. Then you can fill up your arrays. I am assuming that you wanted each line in it's own array and that you wanted unlimited arrays. The best way to do that is to have an array of arrays.
std::string Line;
std::array<std::array<string>> Data;
while (std::getline(infile, Line))
{
std::stringstream ss;
ss << Line;
Data.push_back(std::vector<std::string>);
std::string Temp;
while (std::getline(ss, Temp, ','))
{
Data[Data.size() - 1].push_back(Temp);
}
}
This way you will have a vector, full of vectors, each of which conatining strings of all your data in that line. To access the strings as numbers, you can use std::stoi(std::string) which converts a string to an integer.
I would like to be able to read the data that I have into C++ and then start to do things to manipulate it. I am quite new but have a tiny bit of basic knowledge. The most obvious way of doing this that strikes me (and maybe this comes from using excel previously) would be to read the data into a 2d array. This is the code that I have so far.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;
string C_J;
int main()
{
float data[1000000][10];
ifstream C_J_input;
C_J_input.open("/Users/RT/B/CJ.csv");
if (!C_J_input) return -1;
for(int row = 0; row <1000000; row++)
{
string line;
getline(C_J_input, C_J, '?');
if ( !C_J_input.good() )
break;
stringstream iss(line);
for(int col = 0; col < 10; col++)
{
string val;
getline(iss, val, ',');
if (!iss.good() )
break;
stringstream converter(val);
converter >> data[row][col];
}
}
cout << data;
return 0;
}
Once I have the data read in I would like to be able to read through it line by line and then pull analyse it, looking for certain things however I think that could probably be the topic of another thread, once I have the data read in.
Just let me know if this is a bad question in any way and I will try to add anything more that might make it better.
Thanks!
as request of the asker, this is how you would load it into a string, then split into lines, and then further split into elements:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
//This takes a string and splits it with a delimiter and returns a vector of strings
std::vector<std::string> &SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
}
int main(int argc, char* argv[])
{
//load the file with ifstream
std::ifstream t("test.csv");
if (!t)
{
std::cout << "Unknown File" << std::endl;
return 1;
}
//this is just a block of code designed to load the whole file into one string
std::string str;
//this sets the read position to the end
t.seekg(0, std::ios::end);
str.reserve(t.tellg());//this gives the string enough memory to allocate up the the read position of the file (which is the end)
t.seekg(0, std::ios::beg);//this sets the read position back to the beginning to start reading it
//this takes the everything in the stream (the file data) and loads it into the string.
//istreambuf_iterator is used to loop through the contents of the stream (t), and in this case go up to the end.
str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
//if (sizeof(rawData) != *rawSize)
// return false;
//if the file has size (is not empty) then analyze
if (str.length() > 0)
{
//the file is loaded
//split by delimeter(which is the newline character)
std::vector<std::string> lines;//this holds a string for each line in the file
SplitString(str, '\n', lines);
//each element in the vector holds a vector of of elements(strings between commas)
std::vector<std::vector<std::string> > LineElements;
//for each line
for (auto it : lines)
{
//this is a vector of elements in this line
std::vector<std::string> elementsInLine;
//split with the comma, this would seperate "one,two,three" into {"one","two","three"}
SplitString(it, ',', elementsInLine);
//take the elements in this line, and add it to the line-element vector
LineElements.push_back(elementsInLine);
}
//this displays each element in an organized fashion
//for each line
for (auto it : LineElements)
{
//for each element IN that line
for (auto i : it)
{
//if it is not the last element in the line, then insert comma
if (i != it.back())
std::cout << i << ',';
else
std::cout << i;//last element does not get a trailing comma
}
//the end of the line
std::cout << '\n';
}
}
else
{
std::cout << "File Is empty" << std::endl;
return 1;
}
system("PAUSE");
return 0;
}
On second glance, I've noticed few obvious issues which will slow your progress greatly, so I'll drop them here:
1) you are using two disconnected variables for reading the lines:
C_J - which receives data from getline function
line - which is used as the source of stringstream
I'm pretty sure that the C_J is completely unnecessary. I think you wanted to simply do
getline(C_J_input, line, ...) // so that the textline read will fly to the LINE var
// ...and later
stringstream iss(line); // no change
or, alternatively:
getline(C_J_input, C_J, ...) // no change
// ...and later
stringstream iss(C_J); // so that ISS will read the textline we've just read
elsewise, the stringstream will never see what getline has read form the file - getline writes the data to different place (C_J) than the stringstream looks at (line).
2) another tiny bit is that you are feeding a '?' into getline() as the line separator. CSVs usually use a 'newline' character to separate the data lines. Of course, your input file may use '?' - I dont know. But if you wanted to use a newline instead then omit the parameter at all, getline will use default newline character matching your OS, and this will probably be just OK.
3) your array of float is, um huge. Consider using list instead. It will nicely grow as you read rows. You can even nest them, so list<list<float>> is also very usable. I'd actually probably use list<vector<float>> as the number of columns is constant though. Using a preallocated huge array is not a good idea, as there always be a file with one-line-too-much you know and ka-boom.
4) your code contains a just-as-huge loop that iterates a constant number of times. A loop itself is ok, but the linecount will vary. You actually don't need to count the lines. Especially if you use list<> to store the values. Just like you;ve checked if the file is properly open if(!C_J_input), you may also check if you have reached End-Of-File:
if(C_J_input.eof())
; // will fire ONLY if you are at the end of the file.
see here for an example
uh.. well, that's for start. Goodluck!
This is my first attempt at writing a program. I am trying to take a text file similar to this:
1 EAME B170 4
It continues the 4 values in columns for hundreds of iterations.
Then use a while loop to input each column into arrays. The data is being input wrong because of my current while loop. I can see from using the step by step debugger that the first column is gathered and placed into "monthDemand" array, but after that everything fails. The EAME is placed into the char region array with other junk data and the "B170" is split. Only the B is assigned to "dealerCode" and the "170" gets assigned to "unitsDemanded" which should be the 4th column of inputs. Here is my function attempting to load the arrays:
void loadDemandArrays (int monthDemand [], char region [], char dealerCode [], int unitsDemanded [], int limitDemand, int maxRegion, int maxDealerCode) {
//open the Demand file and abort the program if file not found
ifstream infileDemand;
infileDemand.open ("Demand.txt");
if (!infileDemand) {
cerr << "Cannot open Demand.txt\n";
exit (1);
}
// Input all data into arrays from the Demand File
int i = 0;
int lineNumberDemand = 1;
while (i < limitDemand && infileDemand) {
infileDemand >> monthDemand[i] >> ws;
infileDemand.get (region, sizeof(region));
infileDemand.get (dealerCode, sizeof(dealerCode));
infileDemand >> unitsDemanded [i];
i++;
lineNumberDemand++;
}
I have been stuck reading resources and retrying edits that are not working. Can someone tell me if what I am trying to do is possible the way I am doing it or suggest a good reference that would explain?
Here's a tiny sample program that should get you started. It reads the file line by line, splits the line by space delimeter and outputs to console the results. There are some restrictions. There should be exactly for groups of characters in each string of the file separated by spaces. The first and the last elements of each string must only contain integer numbers.
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
std::vector<std::string> split(const std::string &s, char delim)
{
std::vector<std::string> elements;
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elements.push_back(item);
}
return elements;
}
int main()
{
std::ifstream file("data.txt", std::ifstream::in);
std::string lineRed;
for (;;)
{
getline(file, lineRed);
if (0 == lineRed.length())
{
break;
}
std::vector<std::string> elems = split(lineRed, ' ');
if (elems.size() == 4)
{
int month = atoi(elems[0].c_str());
std::string code = elems[1];
std::string region = elems[2];
int amount = atoi(elems[3].c_str());
//Do something with extracted values here
//Just print 'em to stdout for the test purpose:
std::cout<< "Month:" << month << " Code:" << code << " Region: " << region << " Amount: " << amount;
}
lineRed.clear();
}
}
I have a program that can successfully read a CSV file. The said CSV file is a list separated by 3 columns. And each column has a comma in between each line. For instance
line 1 --- artist, genre, song
line 2 --- Michael jackson, Pop, thriller
and so on. What I want my program to do is read the first line and to take artist, genre, and song, print those out to the user as options. For instance
"Choose an Option"
1. Artist
2. Genre
3. Song
and then when they select an option it then shows them either all the artists, songs, or genres in the CSV file.
So far I have my program reading the CSV and putting each line in a vector. Here is my code so far ...
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
ifstream infile("music_list.csv");
string line = "";
vector<string> all_words;
cout << "Hello";
while (getline(infile, line))
{
stringstream strstr(line);
string word = "";
while (getline(strstr,word, ','))
{
all_words.push_back(word);
}
for (unsigned i = 0; i < all_words.size(); i++)
{
cout << all_words.at(i)<< "\n";
}
}
system("pause");
return 0;
}
I'm just having trouble figuring out how to have it read the first line, separate each string in the first line that is already separated by a comma and have that then outputted to the user as an option. So in essence I can change artist, genre, song to something like appetizers, dish, drinks in the CSV file.
First you have to read the csv file and store the lines in a vector, You can use this function to do that.
vector<string> readCsvFileContent(const string file)
{
vector<string> buffer;
ifstream configFile;
configFile.exceptions(ifstream::badbit);
try
{
configFile.open(file.c_str(),ifstream::in);
if(configFile.is_open())
{
string line;
while (getline(configFile,line))
{
buffer.push_back(line);
}
configFile.close();
}
}
catch (ifstream::failure e){
throw e;
}
return buffer;
}
Then split the each line entry to 2D vector. for that you can use this function
vector<vector<string>> processCsvList(vector<string> csvList)
{
#define SINGER_CONFIG_COUNT 3 //number of comma separated data suppose to be in one line.
#define DELIMITED_CHAR ","
#define EMPTY_STRING "";
vector<vector<string>> tempList;
string configCell ="";
for(vector<string>::iterator it = csvList.begin(); it != csvList.end(); ++it)
{
if(*it == EMPTY_STRING)
{
continue;
}
stringstream configLine(*it);
vector<string> tempDevice;
for(int i=0; i<SINGER_CONFIG_COUNT; i++)
{
if(getline(configLine,configCell,DELIMITED_CHAR))
{
tempDevice.push_back(configCell);
}else
{
tempDevice.push_back(EMPTY_STRING);
}
}
tempList.push_back(tempDevice);
}
return tempList;
}
I haven't try to compile any of these function, because I do not have environment to do so here. But I think this will help to to think about the direction.
now your data in a 2D vector like excell sheet. So you can access by the index of the inner vector.
You could create a std::map<string,vector<string>> so that you could then store each column of the CSV file from line 2 onwards in the map as a vector of strings, keyed by the text that appears in the column on line 1 of the CSV file.
Then you could present the names of the fields by iterating through the keys of the std::map, which are conveniently stored in alphabetical order.
The task of reading in the first line of the CSV file could be performed by the code you already have, or something more sophisticated that takes into account the quoted fields, etc. that are found in fully-featured CSV files.