C++ with Boost Library. Reading Columns. Excel/CSV - c++

I'm reading in a CSV that has 3 columns. On each column I need to perform the mean, var, and std calculations. I'm able to get the output for the first column but dont know how to have it print all 3 columns. Thanks.
I tried adding ','
after line
in
while (getline(inNew, line, ','))
but that doesnt work for me
int main()
{
ifstream inNew("C:/Users/A.csv");
accumulator_set<double, stats<tag::mean, tag::variance >> acc;
if (inNew)
{
string line;
while (getline(inNew, line))
{
acc(stod(line));
}
cout << "Expected return is: " << mean(acc) << std::endl;
cout << "Variance: " << variance(acc) << std::endl;
cout << "Std Dev: " << sqrt(variance(acc)) << std::endl;
}
inNew.close();
system("pause");
return 0;
}

Since you're already using boost, use boost::split to split each line into its columns. Then accumulate each column separately. You'll need an accumulator_set for each column.
Code might look something like this:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/variance.hpp>
#include <boost/algorithm/string.hpp>
int main()
{
using namespace std;
using namespace boost;
using namespace boost::accumulators;
ifstream inNew("C:/Users/A.csv");
size_t columns = 3;
vector<accumulator_set<double, stats<tag::mean, tag::variance>>> acc(columns);
if (inNew)
{
string line;
while (getline(inNew, line))
{
vector<string> strs;
split(strs, line, is_any_of("\t ,"));
if (strs.size() == columns)
{
for (size_t i = 0; i < columns; ++i)
{
acc[i](stod(strs[i]));
}
}
}
for (size_t i = 0; i < columns; ++i)
{
cout << "Stats for column " << (i + 1) << endl;
cout << "Expected return is: " << mean(acc[i]) << endl;
cout << "Variance: " << variance(acc[i]) << endl;
cout << "Std Dev: " << sqrt(variance(acc[i])) << endl;
}
}
inNew.close();
system("pause");
return 0;
}
Of course, you could make this more fancy and robust by not hardcoding the number of columns.

Related

Creating new txt files with c++ program, naming with variables

I have created a program and I want to create with it files like aff1.txt, aff2.txt, etc. In these files, I want to have here a text created this way: It will open the file: text.txt and it will take each sentence, copy it 4700/sentence length times to each file. But it isn't working, when: cout << ss << endl;, it writes to cmd nothing, while there should be something, which was assigned before. What should I do?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <string.h>
#include <sstream>
using namespace std;
int main()
{
ifstream vstup("text.txt"); // 4700,2700,2200,1700
string vety;
getline(vstup,vety);
vstup.close();
string ss="affn.txt";
char q[vety.length()];
for (int u=0;u<vety.length();u++)
{
q[u] = vety[u];
}
int l=0,m=0,n=0;
int v,i,e,o;
char vl[999999];
//cout << vety.length() << endl;
for (i=0;i<vety.length();i++)
{
//cout << "ss" << endl;
if (q[i]=='.')
{
// cout << "ss" << endl;
v=4700/i;
for (e=0;e<v;e++)
{
//cout << "ss" << endl;
for (o=0;o<i-l;o++)
{
// cout << "ss" << endl;
m=o+e*(i-l);
vl[m]=q[o+l];
}
}
l=l+i;
cout << vl << endl;
n++;
//ofstream aff("aff.txt");
//aff << vl << endl;
//aff.close();
ss[3]=n;
ofstream writer(ss.c_str());
//writer.open(ss.c_str());
writer << vl << endl;
writer.close();
cout << ss << endl;
ss.clear();
}
}
return 0;
}

Why does my vector::erase call throw "vector subscript out of range"?

I'm writing a program that saves words from a .txt file in vector words, calculates how many words are there (num_elements) and prints these words randomly to the screen (no duplicates).
It all works fine up until rw.erase line, which just spits out the error "vector subscript out of range".
Why is my erase call throwing "vector subscript out of range"?
#include <iostream>
#include <string>
#include <fstream>
#include <Windows.h>
#include <direct.h>
#include <filesystem>
#include <time.h>
#include <random>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
void path_to_main_dir() {
string path = "C:/Randomizer/";
for (const auto& entry : experimental::filesystem::directory_iterator(path)) {
cout << entry.path() << endl;
}
}
int main() {
path_to_main_dir();
string dateread;
printf("Which file do you want to open? ");
cout << "---------------------------------------------------------------------------------------------------------" << endl;
path_to_main_dir();
cout << endl;
cout << "---------------------------------------------------------------------------------------------------------" << endl;
cout << "User: ";
getline(cin, dateread);
string path_to_file = "C:/Randomizer/" + dateread + ".txt";
ifstream readfile(path_to_file.c_str());
vector<string> words;
string word;
while (getline(readfile, word))
{
words.push_back(word);
}
readfile.close();
srand(time(NULL));
string randomword;
vector<string> rw = { words };
int num_elements = size(words);
cout << endl;
cout << "Number of words in the file: ";
cout << num_elements;
cout << endl;
for (unsigned int a = 0; a < num_elements; a = a + 1)
{
randomword = rw[rand() % num_elements];
cout << randomword << endl;
rw.erase(remove(rw.begin(), rw.end(), randomword), rw.end());
num_elements -= 1;
system("pause");
}
goto firstline;
return 0;
}
If the error only happens in the case where there are duplicates, it could be because the num_elements is wrong. The remove/erase call will have deleted as many duplicates as there are, but num_elements has only been reduced by one.
Fortunatly, vectors know their own size, so rather than trying to remember its internal information for it, you can just ask!
int main()
{
//...
//Code to read words from file
//...
cout << "Number of words in file: " << words.size() << endl;
while(!words.empty())
{
string randomWord = words[rand() % words.size()];
cout << randomWord << endl;
words.erase(remove(words.begin(), words.end(), randomWord), words.end());
}
return 0;
}
From what I can see, you only use words to create rw, so we could just use words directly instead.

ifstream::read not working?

I am trying to read from a .csv file. There are two functions below, one for writing and one for reading.
The file contains a simple table:
date,first,second
1 a one
2 b two
3 c three
4 c four
For some reason, the statement while(file_stream.read(&c,1)); does not read anything. It stops at the first character and I'm dumbfounded as to why. Any clues?
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
std::string filename;
std::string line_string;
ifstream file_stream;
stringstream ss;
vector< vector<string> > vec;
char c;
void read_file()
{
filename = "test.csv";
cout << filename << endl;
file_stream.open(filename.c_str(),ios::out|ios::binary);
if(file_stream.fail())
{
cout << "File didn't open" << endl;
return;
}
if(file_stream.is_open())
cout << "file opened" << endl;
while(file_stream.read(&c,1)); // this isn't working
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
file_stream.close();
cout << "string is: " << ss.str() << endl;
//get each line
int counter = 0;
vector<string> invec;
while(getline(ss,line_string,'\n'))
{
string header_string;
stringstream header_stream;
header_stream << line_string;
while(getline(header_stream, header_string,','))
{
invec.push_back(header_string);
}
invec.push_back(header_string);
vec.push_back(invec);
invec.clear();
counter++;
}
}
void test_output()
{
for(int i = 0; i < vec.size();i++)
{
for(int in = 0; in < vec[0].size(); in++)
cout << vec[i][in] << " ";
cout << endl;
}
}
int main()
{
read_file();
test_output();
}
Look very very carefully at the line that is not working:
while(file_stream.read(&c,1)); // this isn't working
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
The ; character at the end of the while statement does NOT belong! You are running a no-body loop that does not terminate until read() fails, and THEN your code enters the bracketed block to output the last character that was successfully read (if any).
You need to remove that erroneous ; character:
while(file_stream.read(&c,1)) // this works
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
Now, the real question is - why are you reading the input file character-by-character into a std::stringstream in the first place? You can use std::getline() with the input std::ifstream directly:
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
std::vector< std::vector<std::string> > vec;
void read_file()
{
std::string filename = "test.csv";
std::cout << filename << std::endl;
std::ifstream file_stream;
file_stream.open(filename.c_str(), ios::binary);
if (!file_stream)
{
std::cout << "File didn't open" << std::endl;
return;
}
std::cout << "file opened" << std::endl;
//get each line
std::vector<std::string> invec;
std::string line;
int counter = 0;
if (std::getline(file_stream, line))
{
std::istringstream iss(line);
while (std::getline(iss, line, ','))
invec.push_back(line);
vec.push_back(invec);
invec.clear();
++counter;
while (std::getline(file_stream, line))
{
iss.str(line);
while (iss >> line)
invec.push_back(line);
vec.push_back(invec);
invec.clear();
++counter;
}
}
}
void test_output()
{
if (!vec.empty())
{
for(int in = 0; in < vec[0].size(); ++in)
std::cout << vec[0][in] << ",";
std::cout << std::endl;
for(int i = 1; i < vec.size(); ++i)
{
for(int in = 0; in < vec[i].size(); ++in)
std::cout << vec[i][in] << " ";
std::cout << std::endl;
}
}
}
int main()
{
read_file();
test_output();
}

Unordered multimap finding all values

I would like to see whether it is possible to see all values that we have emplaced. For example:
#include <iostream>
#include <unordered_map>
using namespace std;
int main () {
unordered_multimap<string,int> hash;
hash.emplace("Hello", 12);
hash.emplace("World", 22);
hash.emplace("Wofh", 25);
for (int i = 1; i < 10; i++) {
hash.emplace("Wofh", i);
}
cout << "Hello " << hash.find("Hello")->second << endl;
cout << "Wofh " << hash.count("Wofh") << endl;
cout << "Wofh " << hash.find("Wofh")->second << endl;
return 0;
}
The output is :
$ ./stlhash
Hello 12
Wofh 10
Wofh 9
Whereas I want the last line to show from 25,1,2... to 9. Apparently find only takes first and second pointer as first is the value and second is the corresponding value. Is there any way to do this?
The operation you need is called equal_range
Example from the cplusplus.com:
// unordered_multimap::equal_range
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
typedef std::unordered_multimap<std::string,std::string> stringmap;
int main ()
{
stringmap myumm = {
{"orange","FL"},
{"strawberry","LA"},
{"strawberry","OK"},
{"pumpkin","NH"}
};
std::cout << "Entries with strawberry:";
auto range = myumm.equal_range("strawberry");
for_each (
range.first,
range.second,
[](stringmap::value_type& x){std::cout << " " << x.second;}
);
return 0;
}

Counting how many times each word occurs in a file using map. (c++)

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <map>
using namespace std;
int main()
{
ifstream fin;
fin.open("myTextFile.txt");
if ( fin.fail()){
cout << "Could not open input file.";
exit(1);
}
string next;
map <string, int> words;
while (fin >> next){
words[next]++;
}
cout << "\n\n" << "Number of words: " << words[next] << endl;
fin.close();
fin.open("myTextFile.txt");
while (fin >> next){
cout << next << ": " << words[next] << endl;
}
fin.close();
return 0;
}
My main problem is that when a word occurs more than once, it is also listed more then once. i.e if the text starts with "hello hello" then cout produces:
"hello: 2" '\n' "hello: 2"
Also, i'd like not to have to close, and then reopen the file for the second while to be true. It seems like its still at the end of the file from the last while loop.
You need to iterate trough the map, and not open the file a second time.
Look at the code sample provided here.
EDIT: here a code sample that iterates trough a map
// map::begin/end
#include <iostream>
#include <map>
int main ()
{
std::map<char,int> mymap;
std::map<char,int>::iterator it;
mymap['b'] = 100;
mymap['a'] = 200;
mymap['c'] = 300;
// show content:
for (std::map<char,int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << it->first << " => " << it->second << '\n';
return 0;
}
Here is the output:
a => 200
b => 100
c => 300
You don't need re-open file:
for (auto i = words.begin(); i != words.end(); i++)
{
cout << i->first << " : " << i->second << endl;
}
or simpler:
for (const auto &i : words)
{
cout << i.first << " : " << i.second << endl;
}
You need to iterate over the map after you set it and then you do not need to open the file again, this is trivial example:
int main()
{
std::map<std::string, int> m1 ;
m1["hello"] = 2 ;
m1["world"] = 4 ;
for( const auto &entry : m1 )
{
std::cout << entry.first << " : " << entry.second << std::endl ;
}
}
The expected output would be:
hello : 2
world : 4