In C++, how to use a two-dimensional dynamic vector to sum up each column for the matrix in the txt file, and print out the content of the txt file and the result of summing up each column?
After searching through the Internet, I got the following code, but it only sums up a single column. The result I want to get is that no matter how many columns there are in the txt file, I can do the sum of each column.
data.txt figure
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
ifstream myfile("data.txt");
if (!myfile.is_open()) {
cout << "Unable to open myfile";
system("pause");
exit(0);
}
vector<string> vec;
string temp;
while (getline(myfile, temp))
{
vec.push_back(temp);
}
vector <float> radius;
cout << "Processing time: " << endl;
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it << endl;
istringstream is(*it);
string s;
int pam = 0;
while (is >> s)
{
if (pam == 0)
{
float r = atof(s.c_str());
radius.push_back(r);
}
pam++;
}
}
cout << "matrix: " << endl;
double sum;
sum = 0;
for (auto it = radius.begin(); it != radius.end(); it++)
{
sum += *it;
}
cout << sum << endl;
system("pause");
return 0;
}
I want to sum each column in the txt file, as shown in the image below:
result
The first thing you should do is not concern yourself with where the data is coming from. Instead, you should write a function that takes the data, regardless of where it comes from, and outputs the totals.
The simplest way to represent the input data is to use a std::vector<std::vector<float>>. Thus a function to create the totals would return a std::vector<float> that represents the totals.
Here is an example of such a function:
#include <vector>
#include <numeric>
// Pass in the data
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
// call std::accumulate for each column i
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
// return the totals
return totals;
}
The above function uses std::accumulate to total the values in column i, and store the total for that column in totals[i].
Once this function is written, it can then be tested. Here is a full example:
#include <vector>
#include <numeric>
#include <iostream>
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
return totals;
}
void printTotals(const std::vector<std::vector<float>>& data,
const std::vector<float>& totals)
{
for (auto& v : data)
{
for (auto& v2 : v)
std::cout << v2 << " ";
std::cout << "\n";
}
std::cout << "Total: ";
for (auto& t : totals)
std::cout << t << " ";
}
int main()
{
std::vector<std::vector<float>> test1 = {{1,2,3},{4,5,6},{7,8,9}};
std::vector<std::vector<float>> test2 = {{1,2,3,4},{4,5,6,8},{7,8,9,10}};
std::vector<std::vector<float>> test3 = {{1,2},{-3,4},{7,8},{34,12},{12,17}};
printTotals(test1, getTotals(test1));
std::cout << "\n\n";
printTotals(test2, getTotals(test2));
std::cout << "\n\n";
printTotals(test3, getTotals(test3));
}
Output:
1 2 3
4 5 6
7 8 9
Total: 12 15 18
1 2 3 4
4 5 6 8
7 8 9 10
Total: 12 15 18 22
1 2
-3 4
7 8
34 12
12 17
Total: 51 43
Once you have this, the next step is to create the std::vector<std::vector<float>> from the data in the file. Once that is created, it is just a simple matter of calling the getTotals() function with that data.
The file reading can be as follows:
#include <istream>
#include <sstream>
#include <vector>
#include <string>
//...
std::vector<std::vector<float>> readData(std::istream& is)
{
std::vector<std::vector<float>> data;
std::string oneLine;
float oneData;
while (std::getline(is, oneLine))
{
std::vector<float> vOneData;
std::istringstream strm(oneLine);
while (strm >> oneData)
vOneData.push_back(oneData);
data.push_back(vOneData);
}
return data;
}
The function is called by simply passing in the stream object (in your case, myfile). The returned value will be a std::vector<std::vector<float>> of the values that were read in.
Putting this all together:
#include <vector>
#include <numeric>
#include <iostream>
#include <istream>
#include <string>
#include <sstream>
std::vector<float> getTotals(const std::vector<std::vector<float>>& myData)
{
std::vector<float> totals(myData[0].size());
for (size_t i = 0; i < totals.size(); ++i)
{
totals[i] = std::accumulate(myData.begin(), myData.end(), 0,
[&](int total, auto& v)
{ return total + v[i]; });
}
return totals;
}
void printTotals(const std::vector<std::vector<float>>& data,
const std::vector<float>& totals)
{
for (auto& v : data)
{
for (auto& v2 : v)
std::cout << v2 << " ";
std::cout << "\n";
}
std::cout << "Total: ";
for (auto& t : totals)
std::cout << t << " ";
}
std::vector<std::vector<float>> readData(std::istream& is)
{
std::vector<std::vector<float>> data;
std::string oneLine;
float oneData;
while (std::getline(is, oneLine))
{
std::vector<float> vOneData;
std::istringstream strm(oneLine);
while (strm >> oneData)
vOneData.push_back(oneData);
data.push_back(vOneData);
}
return data;
}
int main()
{
std::string fileData = "2 3 4 1 5 2\n6 1 2 6 1 8\n8 7 3 9 6 4";
std::istringstream fileDataStream(fileData);
auto dataFromFile = readData(fileDataStream);
printTotals(dataFromFile, getTotals(dataFromFile));
}
Output:
2 3 4 1 5 2
6 1 2 6 1 8
8 7 3 9 6 4
Total: 16 11 9 16 12 14
Note that I didn't use a file stream, but a stringstream to illustrate it doesn't matter how the data is created.
Related
I'm new to c++, I'm trying to read values from a text file and push only the integers to a stack. The issue I'm having is that when I do a pop() the value that comes out of the stack is different.
For example if I push a 4, when I do a pop it comes out as 52.
What am I doing wrong and how can I fix it?
IntegerStack.cpp
#include "IntegerStack.h"
#include <cstdlib>
using namespace std;
IntegerStack::IntegerStack()
{
used = 0;
}
void IntegerStack::push(int entry)
{
data[used] = entry;
++used;
}
int IntegerStack::pop()
{
--used;
return data[used];
}
int IntegerStack::peek() const
{
return data[used-1];
}
IntegerStack.h
#ifndef INTEGERSTACK_H
#define INTEGERSTACK_H
#include <cstdlib> // Provides the type size_t.
using namespace std;
class IntegerStack
{
public:
// MEMBER CONSTANT
static const std::size_t CAPACITY = 100;
// DEFAULT CONSTRUCTOR
IntegerStack( ); // Inline
// MODIFICATION MEMBER FUNCTIONS
void push ( int entry );
int pop ( );
// CONSTANT MEMBER FUNCTIONS
std::size_t size ( ) const { return used; } // Inline
bool is_empty ( ) const { return used == 0; } // Inline
int peek ( ) const;
private:
// DATA MEMBERS
int data[CAPACITY];
std::size_t used;
};
#endif // INTEGERSTACK_H
main.cpp
#include <fstream>
#include <iostream>
#include "IntegerStack.h"
using namespace std;
int main()
{
string content;
ifstream inputFile;
cout << "Enter input file name: ";
cin >> content;
IntegerStack operandStack;
// Open file
inputFile.open(content.c_str());
if(inputFile)
{
// Place values in the stack
while(getline(inputFile,content))
{
cout << "Expression: " << content << endl;
for (int i = 0; i < content.size(); i++)
{
if(isdigit(content[i]))
{
cout << "Adding " << content[i] << " to operandStack" << endl;
operandStack.push(content[i]);
int number = operandStack.pop();
cout << "The integer we just pushed: " << number << endl;
}
else
{
// add it to operatorStack
}
}
}
}
// Close file
inputFile.close();
return 0;
}
inix.dat
8 + 4 / 2
( 7 * 4 ) - 2
OUTPUT
Enter input file name: infix.dat
Expression: 8 + 4 / 2
Adding 8 to operandStack
The integer we just pushed: 56
Adding 4 to operandStack
The integer we just pushed: 52
Adding 2 to operandStack
The integer we just pushed: 50
Expression: ( 7 * 4 ) - 2
Adding 7 to operandStack
The integer we just pushed: 55
Adding 4 to operandStack
The integer we just pushed: 52
Adding 2 to operandStack
The integer we just pushed: 50
Process returned 0 (0x0) execution time : 4.762 s
Press any key to continue.
I was able to solve this by changing operandStack.push(content[i]); to operandStack.push(content[i]- '0');
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
This code is supposed to read in from a file and store the information. Here's the file:
5
Franks,Tom 2 3 8 3 6 3 5
Gates,Bill 8 8 3 0 8 2 0
Jordan,Michael 9 10 4 7 0 0 0
Bush,George 5 6 5 6 5 6 5
Heinke,Lonnie 7 3 8 7 2 5 7
right now I'm just focused on saving pointers to the names. Here's the code I have so far (Ignore the other functions I haven't gotten to those yet). I have to save the names using employees[row] = new Employee; and fin >> employees[row]->names; and I just don't know how to go about doing that.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
using namespace std;
struct Employee {
string names;
vector<int> data;
int totalHrs;
};
int fillAndTotal(vector<Employee *>&employees);
void sort(vector<Employee *>&employees, int amount);
void output(vector<Employee *>&employees, int amount);
int main()
{
vector<Employee *>employees;
//vector<string>names;
int amount = 0;
amount = fillAndTotal(employees);
sort(employees, amount);
output(employees, amount);
system("pause");
return 0;
}
int fillAndTotal(vector<Employee *>&employees) {
int const TTL_HRS = 7;
ifstream fin;
fin.open("empdata.txt");
if (fin.fail()) {
cout << "ERROR";
}
int sum = 0;
int numOfNames;
fin >> numOfNames;
string tmpString;
int tempInt = 0;
vector<int>temp(8);
for (int row = 0; row < numOfNames; row++) {
employees[row] = new Employee;
fin >> employees[row]->names;
Firstly, you don't need pointers for this - your Employee structure is perfectly safe to store as-in in a vector.
Secondly, when reading line-orientated data like this, it's very easy to get off-track and let your reads overflow into the next line, or underflow and you not carry out enough reads for the line - what I do is write a function that reads a whole line at a time and returns a stringstream containing just that line, then I do my individual reads on that stringstream.
Thirdly, and finally, it's always useful to write functions that allows you to dump out your data structures so that you can confirm visually that you've populated the structures correctly. Or you can use a debugger.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Employee
{
std::string names;
std::vector<int> data;
int totalHrs;
};
using EmpList = std::vector<Employee>;
int fillAndTotal(EmpList& employees);
std::stringstream readRowData(std::istream& fin);
#ifndef NDEBUG
// Debug - dump to stream.
std::ostream& operator<<(std::ostream& out, const Employee& employee);
std::ostream& operator<<(std::ostream& out, const EmpList& employees);
#endif
int main(int argc, char* argv[])
{
EmpList employees;
auto grandTotal = fillAndTotal(employees);
std::cout << employees;
std::cout << "\nGrand total hours: " << grandTotal << std::endl;
}
int fillAndTotal(EmpList& employees)
{
auto fin = std::ifstream("empdata.txt");
auto rowCount = 0;
auto rowData = readRowData(fin);
rowData >> rowCount;
auto totalHours = 0;
for (auto i = 0; i < rowCount; ++i)
{
rowData = readRowData(fin);
if (!fin.eof())
{
auto employee = Employee{};
rowData >> employee.names;
int hours;
while (rowData >> hours)
{
if (hours != 0)
{
employee.data.push_back(hours);
employee.totalHrs += hours;
totalHours += hours;
}
}
employees.push_back(employee);
}
}
return totalHours;
}
std::stringstream readRowData(std::istream& fin)
{
std::stringstream rowStream;
std::string rowData;
if (getline(fin, rowData))
{
rowStream.str(rowData);
}
return rowStream;
}
#ifndef NDEBUG
std::ostream& operator<<(std::ostream& out, const Employee& employee)
{
out << "Name: " << employee.names << '\n';
out << "Total hours: " << employee.totalHrs << '\n';
out << "Individual hours:";
for (auto const &hours : employee.data)
{
out << ' ' << hours;
}
out << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const EmpList& employees)
{
auto first = true;
for (auto const &employee : employees)
{
if (first)
{
first = false;
}
else
{
out << '\n';
}
out << employee;
}
return out;
}
#endif
Now your output function is already written for you, and you just need to write your sort.
I have a list of data (in 4 columns) that I would like to sort by a certain column. It was read in from a file to a 2D vector. I the used the std::sort method and wrote my comparator functor. The program compiles and runs, but when I print the first 10 elements it is not sorted, but is certainly different from the order it was added to the 2D vector.
Here is the code:
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;
typedef vector<double> Row;
typedef vector<Row> Matrix;
bool sortByFourthColumn(const Row& row1, const Row& row2){
return (double) row1[3] < (double) row2[3];
}
int main(){
std::ifstream infile;
infile.open("Test8_Output.txt");
double x,y,z,E;
char line[200];
int line_count=0;
ofstream outfile;
outfile.open("WO_crp.txt");
if (infile.is_open()){
while (!infile.eof()){
infile.getline(line,170);
if (line[0] != '%'){
outfile<<line<<"\n";
line_count++;
}
else{
}
}
Matrix data(line_count,Row(4));
outfile.close();
std::ifstream myfile;
myfile.open("WO_crp.txt");
int i = 0;
while(myfile >> x >> y >> z >> E){
data[0][i] = x;
data[1][i] = y;
data[2][i] = z;
data[3][i] = E;
i++;
}
myfile.close();
std::sort(data.begin(), data.end(), sortByFourthColumn);
for (int u = 0; u <20; u++){
cout << setprecision(5) << data[0][u] << "\t" << setprecision(5)<< data[1][u] << "\t" << setprecision(5)<< data[2][u] << "\t" << setprecision(5)<< data[3][u] << endl;
}
}
else{
cout << "Error: File is invalid.\n";
}
return(0);
}
EDIT - Sample of what the input file looks like:
EDIT 2 - swapped 4 and line_count in Matrix data(4,Row(line_count));
% Model: CDS_Test8.mph
% Version: COMSOL 5.2.0.220
% Date: Jul 13 2016, 14:33
% Dimension: 3
% Nodes: 86183
% Expressions: 1
% Description: Electric field norm
% Length unit: m
% x y z es.normE (V/m)
0.13774675805195374 0.05012986567931247 0.20735 67.35120820901535
0.13870000000000005 0.04957489750396299 0.20735000000000003 102.8772500513651
0.13870000000000002 0.050800000000000005 0.20735 87.56008679032011
0.13792733849817027 0.050131465727838186 0.20801419247484804 73.55192534768238
0.13674627634411463 0.04992349737428063 0.20735 63.23018910026428
0.13750191177019236 0.0508 0.20735000000000003 67.26176884022838
0.13827743496772454 0.05193409099097887 0.20734999999999998 73.35474409597487
0.13803618792088135 0.05134931748395268 0.20841988134890965 75.3712126982815
0.13905949760011943 0.05141879754884912 0.20734999999999998 83.70739713476813
0.13896970815034013 0.05092428105421264 0.208142746399683 84.73571510992372
0.1390220807917094 0.0501245422629353 0.20817502757007986 85.57119242707628
0.13944867847480893 0.05161480113017738 0.2081969878426443 89.65643851109644
And so on it goes for another 87k lines or so.
I have a list of data (in 4 columns) that I would like to sort by a
certain column.
The problem is that the dimensions of the vector of vectors used to store the data in OP program is not consistent between declaration and use.
A minor problem is the use of while(!infile.eof()){... which should be avoided.
A fixed version is like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <array>
#include <algorithm>
#include <iomanip>
using Row = std::array<double,4>; // instead of typedefs
using Matrix = std::vector<Row>;
using std::cout;
bool sortByFourthColumn(const Row& row1, const Row& row2){
return row1[3] < row2[3];
// ^ The cast is unnecessary
}
int main(){
std::string file_name{"Test8_Output.txt"};
std::ifstream infile{file_name, std::ios_base::in};
if ( !infile ) {
cout << "Error: unable to open file " << file_name << '\n';
return EXIT_FAILURE;
}
Matrix data;
data.reserve(90000); // if you are afraid of the reallocations
int count = 0;
std::string line;
// instead of two loops you can use one loop and read the file once
// I'll use std::getline to extract a row in a std::string
while ( std::getline(infile, line) ) {
// skip comments and empty lines
if ( line.empty() || line[0] == '%' )
continue;
++count;
// extract data from the string using a stringstream
std::stringstream ss{line};
Row r;
ss >> r[0] >> r[1] >> r[2] >> r[3];
if ( !ss ) {
cout << "Format error in line " << count << " of file.\n";
break;
}
data.push_back(std::move(r));
}
std::sort(data.begin(), data.end(), sortByFourthColumn);
cout << std::setprecision(5) << std::fixed;
for ( const auto & r : data ) {
for ( auto const &x : r ) {
cout << std::setw(10) << x;
}
cout << '\n';
}
return EXIT_SUCCESS;
}
The output, given the example data is:
0.13675 0.04992 0.20735 63.23019
0.13750 0.05080 0.20735 67.26177
0.13775 0.05013 0.20735 67.35121
0.13828 0.05193 0.20735 73.35474
0.13793 0.05013 0.20801 73.55193
0.13804 0.05135 0.20842 75.37121
0.13906 0.05142 0.20735 83.70740
0.13897 0.05092 0.20814 84.73572
0.13902 0.05012 0.20818 85.57119
0.13870 0.05080 0.20735 87.56009
0.13945 0.05161 0.20820 89.65644
0.13870 0.04957 0.20735 102.87725
This question already has answers here:
How to parse a string to an int in C++?
(17 answers)
c++ parse int from string [duplicate]
(5 answers)
Closed 8 years ago.
I wanted to know how I can grab numbers out of a string in C++. I'm getting the string from an input and will be getting multiple lines, but I already have the line reading working.
Note: the lines always have an even number of ints
Here's what I'd like the code to look something like:
std::getline(std::cin, line);// line looks something like "10 3 40 45 8 12"
int a, b;
while(!line.empty() /*line still has ints to extract*/) {
a = someMethod(line);//gets first int. So, 10 first loop, 40 second, 8 third
b = someMethod(line);//gets second int. So, 3 first loop, 45 second, 12 third
myMethod(a,b);//a method from elsewhere in my code. It's here so you know that I need both a and b
}
Anything similar would help. Thank you very much!
Here is a complete example.
#include <sstream>
#include <string>
#include <iostream>
int main(){
std::string line = "2 4 56 6";
std::stringstream stream(line);
int i;
while (stream >> i) {
std::cout << i << std::endl;
}
}
The following works fine also, so reading multiple lines should not be a problem.
#include <sstream>
#include <string>
#include <iostream>
int main(){
std::string line = "2 4 56 6";
std::stringstream stream(line);
int i;
while (stream >> i) {
std::cout << i << std::endl;
}
line = "32 62 44 6 22 58 34 60 71 86";
stream.clear();
stream.str(line);
int a,b;
while(stream >> a && stream >> b){
std::cout << a << " " << b << "\n";
}
}
Get tokens from string line and use them as you want.
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
using namespace std;
typedef boost::tokenizer<boost::char_separator<char> >
tokenizer;
void myMethod(int a, int b)
{
cout<<a<<" "<<b<<endl;
}
void getNumber(string line)
{
boost::char_separator<char> sep(" ");
tokenizer tokens(line, sep);
string evenStr, oddStr;
for(tokenizer::iterator iterToken=tokens.begin();
iterToken != tokens.end(); ++iterToken)
{
evenStr = *iterToken;
++iterToken;
if(iterToken != tokens.end())
{
oddStr = *iterToken;
myMethod(atoi(evenStr.c_str()), atoi(oddStr.c_str()));
}
}
}
int main()
{
string line("10 3 40 45 8 12");
getNumber(line);
return 0;
}
You can do like this:
string line;
getline(std::cin, line);// line looks something like "10 3 40 45 8 12"
int a, b;
vector<string> tokens;
istringstream iss(line);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
stringstream s;
for (int i=0;i<tokens.size()/2;i++)
{
s<< tokens[i];
s>>a;
s.clear();
s<<tokens[i+2];
s>>b;
s.clear();
myMethod(a,b);
}
There are multiple ways to achieve this. I prefer to use boost.
Example:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
int main()
{
std::string line = "10 3 40 45 8 12 9"; //std::getline(std::cin, line);// line looks something like "10 3 40 45 8 12"
std::vector<std::string> intNumbers;
std::string s;
boost::split(intNumbers, line, boost::is_any_of(" "), boost::token_compress_on);
unsigned int i=0;
while(i < intNumbers.size())
{
try{
int a = boost::lexical_cast<int>(intNumbers[i++]);
if(i >= intNumbers.size())
{
std::cout << "invlaid values" << std::endl;
break;
}
int b = boost::lexical_cast<int>(intNumbers[i++]);
std::cout << "value a: " << a << std::endl;
std::cout << "value b: " << b << std::endl;
std::cout << "my method (multiply) a*b: " << (a*b) << std::endl;
}
catch(boost::bad_lexical_cast &e)
{
std::cout << "invlaid values" << std::endl;
}
}
}
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> a;
a.push_back("1 1 2 4");
a.push_back("2 3 3 3");
a.push_back("2 2 3 5");
a.push_back("3 3 3 3");
a.push_back("1 2 3 4");
for (int i=0;i<a.size();i++)
for(int j=0;j<a[i].length();j++)
cout<<a[i].at[j];
return 0;
}
Hi,when I run the code above,there is an error as below:
error C2109: subscript requires array or pointer type
Please help me and tell me why,thanks!
at is a function, need to be called with () not []
update
cout<<a[i].at[j];
// ^^^
to
a[i].at(j)
// ^^^^^
To output string, you don't need to cout each char, just do
for (int i=0; i<a.size(); i++)
{
std::cout << a[i] << "\n";
}
std::cout << std::endl;
Or if C++11:
for(auto const & s : a)
{
cout << s << "\n";
}
It is more simpler to use the range-based for statement. For example
for ( const std::string &s : a )
{
for ( char c : s ) std::cout << c;
std::cout << std::endl;
}