I need to sum 100, 200, 300 in a.txt
a.txt
2323|A|5|0|2|100
2424|B|6|1|3|200
2525|C|7|2|4|300
so I opened this file, and read line by line using getline(), and tokenized.
main.cpp
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
for (int i = 0; i < tokens.size(); i++) {
std::cout << tokens[i] << std::endl;
tokens.pop_back();
}
}
As expected, that code printed singly of all things.
so I thought using token index to sum values. but my code have error.
"vector subscript out of range" or no compile.
first try
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
for (int i = 0; i < tokens.size(); i++) {
std::cout << tokens[i] << std::endl;
tokens.pop_back();
std::cout << tokens[5] << std::endl;
std::cout << tokens[11] << std::endl;
std::cout << tokens[17] << std::endl;
int a = 0;
int b = 0;
int c = 0;
int sum = 0;
a = stoi(tokens[5]);
b = stoi(tokens[11]);
c = stoi(tokens[17]);
sum = (a + b + c);
std::cout << sum << std::endl;
}
}
second try
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
if(tokens.size() > 4) {
for (int k = 0; k < ((tokens.size() - 5) / 6) + 1; k++) {
int sum = 0;
int change = 0;
int j = 0;
j = 6 * k + 5;
change = stoi(tokens[j]);
sum += change;
std::cout << sum << std::endl;
tokens.pop_back();
}
}
}
what should I do sum value? and I'm wondering that tokens.size()`s meaning except meaning "size" because second for statement always get an error if not exactly correcting i < tokens.size()
You are modifying the tokens vector while you are looping through it. Don't do that. You are affecting its size(), which accounts for why you are able to go out of bounds.
You say that you need to sum only the last token of each line. But that is not what your code is trying to do. There is no need for an inner for loop at all. Simply split each line into a local tokens vector and then use tokens.back() to get the last token, eg:
std::string line;
int sum = 0;
while (std::getline(inFile, line))
{
std::istringstream iss(line);
std::vector<std::string> tokens;
std::string token;
while (std::getline(iss, token, '|')) {
tokens.push_back(token);
}
// use tokens as needed...
token = tokens.back();
sum += std::stoi(token);
}
std::cout << sum << std::endl;
Live Demo
I would like to structure my code slightly differently.
Rather than try and do everything in the main function split your code up so that you read each line and validate it is correct:
#include <iostream>
#include <string>
// A structure representing the data we want to parse.
struct DataLine
{
int v1;
char c;
int v2;
int v3;
int v4;
int v5;
// An input operator that will read one line of data.
// If the data is valid will update the variable we are reading into.
friend std::istream& operator>>(std::istream& str, DataLine& data)
{
DataLine tmp;
char s[5];
std::string extra;
if ( str >> tmp.v1 >> s[0] && s[0] == '|'
&& str >> tmp.c >> s[1] && s[1] == '|'
&& str >> tmp.v2 >> s[2] && s[2] == '|'
&& str >> tmp.v3 >> s[3] && s[3] == '|'
&& str >> tmp.v4 >> s[4] && s[4] == '|'
&& str >> tmp.v5
&& std::getline(str, extra) && extra.empty())
{
// all the data was read and the line was valid.
// update the correct variable.
swap(tmp, data);
}
else {
// there was an issue.
// set the stream to bad so that reading will stop.
str.setstate(std::ios::badbit);
}
return str;
}
// Standard swap method.
friend void swap(DataLine& lhs, DataLine& rhs) noexcept
{
using std::swap;
swap(lhs.v1, rhs.v1);
swap(lhs.c , rhs.c );
swap(lhs.v2, rhs.v2);
swap(lhs.v3, rhs.v3);
swap(lhs.v4, rhs.v4);
swap(lhs.v5, rhs.v5);
}
};
Then the loop you use to read the data becomes really trivial to implement.
int main()
{
DataLine data;
int sum = 0;
// Now we can read the data in a simple loop.
while(std::cin >> data) {
sum += data.v5;
}
std::cout << "Sum: " << sum << "\n";
}
Related
I've started working on hackerrank/hackerearth like sites. There i've found one problem fetching input. Its easy in Java.
Consider a very simple problem of reading input and displaying it :
Flow is like :
read A
repeat A times
read X1,N1,X2,N2 ; where Xi is any string, Ni is any integer.
display X1+X2, N1+N2
i don't know how to read X1,N1,X2,N2 where X1 and X2 are strings, i've also tried but problem is that when i read first string it reads entire line for eg when i read string it supposed to be X1 but it is X1,N1,X2,N2. code that i used is
scanf("%s,%d,%s,%d", x1, &n1, x2, &n2)
thanks in advance and sorry for my bad english.
Update#1:
example lines :
3
some,123,thing,456
something,579
a,1,b,2
ab,3
hello,100,world,100
helloworld,200
I think you are looking for something like this:
int number_of_inputs;
std::cin >> number_of_inputs;
for (int iteration = 0; iteration < number_of_inputs; ++iteration){
int integer1, integer2;
string string1, string2, stupid_comma;
std::cin >> string1 >> stupid_comma >> integer1 >> stupid_comma >> string2 >> stupid_comma >> integer2;
std::cout << string1 << " + " << string2 << " = " << integer1+integer2 << std::endl;
}
edit2: After op provides input, my code is not correct. Check this answer: Parsing a comma-delimited std::string
edit3: alternative split method op requires:
std::vector<std::string> split(const std::string &text, char sep, int num)
{
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
int elements = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
if ( elements == num) break;
tokens.push_back(text.substr(start, end - start));
start = end + 1;
elements++;
}
tokens.push_back(text.substr(start));
return tokens;
}
edit4: new code using split function:
int number_of_inputs;
std::cin >> number_of_inputs;
for (int iteration = 0; iteration < number_of_inputs; ++iteration){
std:string line;
cin >> line;
int integer1, integer2;
string string1, string2, stupid_comma;
std::vector<std::string> my_line = split(line, ',', 4);
string1 = my_line[0];
string2 = my_line[2];
integer1 = stoll(my_line[1], nullptr, 10);
integer2 = stoll(my_line[3], nullptr, 10);
std::cout << string1 << " + " << string2 << " = " << integer1+integer2 << std::endl;
}
Here is a solution using std::regex, even though it is longer than the accepted answer, I find it much clearer and more flexible.
#include <iostream>
#include <string>
#include <regex>
using namespace std;
struct MyPair {
string x; int n;
MyPair() {}
MyPair( const string& x, int n )
: x(x), n(n) {}
};
void parse_line( const string& str, MyPair& p1, MyPair& p2 ) {
typedef regex_iterator<string::const_iterator> re_iterator;
typedef re_iterator::value_type re_iterated;
regex re("(\\w+),(\\d+),(\\w+),(\\d+)");
re_iterator rit( str.begin(), str.end(), re );
re_iterator rend;
if ( rit != rend ) {
p1 = MyPair( (*rit)[1], stoi((*rit)[2]) );
p2 = MyPair( (*rit)[3], stoi((*rit)[4]) );
}
}
int main() {
int A = 0;
while ( A <= 0 ) {
cin >> A;
}
string line;
MyPair p1, p2;
for ( int i = 0; i < A; i++ ) {
cin >> line;
parse_line( line, p1, p2 );
cout << (p1.x + p2.x) << " " << (p1.n + p2.n) << endl;
}
}
Note that it uses features from C++11, so in order to compile it using clang++ (for instance), you should do:
clang++ -std=c++11 file.cpp -o file
I have to read from a .txt file and out it with a different .txt file. I have to use insertion sort in order to sort them based on two numbers. I could only get this far, I don't know how to do insertion sort in this program where I have two numbers to sort to.
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(void)
{
int serialno[100], suratno[100], ayatno[100];
string order;
string str;
char ch;
int i = 0;
int j, temp;
ifstream fin;
fin.open("text.txt");
if(!fin)
{
cout << "Cannot open file \'text.txt\'! Quitting.\n";
exit(0);
}
while(fin)
{
fin.get(ch); //gets .
getline(fin, order, '('); //allegedly it removes the delimiter char from stream too
fin >> suratno;
fin.get(ch); //gets :
fin >> ayatno;
fin.get(ch); //gets )
fin.get(ch); //gets \n
cout << serialno << "." << order << "("<<suratno<<":<<ayatno<<")\n";
}
fin.close();
//sort algorithm
for (int i = 0; i < length; i++){
j = i;
while (j > 0 && suratno [j] < suratno [j-1]){
temp = suratno [j];
suratno [j] = suratno [j-1];
suratno [j-1] = temp;
j--;
cout << serialno << endl;
}
}
}
ofstream fout;
fout.open("newtext.txt");
if(!fout)
{
cout << "Cannot open output file\'orderedquranorders.txt\'!Quitting.\n";
exit(0);
}
i = 0;
//write sorted list to output file
fout.close();
cout << i << " orders successfully sorted and written.\n";
}
this is the text file (numbers in bracket should be used, firstly with number before colon, and secondly with number after colon):
1. Do not be rude in speech (3:159)
2. Restrain Anger (3:134)
3. Be good to others (4:36)
4. Do not be arrogant (7:13)
5. Forgive others for their mistakes (7:199)
6. Speak to people mildly (20:44)
7. Lower your voice (31:19)
8. Do not ridicule others (49:11)
9. Be dutiful to parents(17:23)
current output:
Do not be rude in speech (3:159)
Restrain Anger (3:134)
Be good to others (4:36)
Be dutiful to parents(17:23)
expected output:
Restrain Anger (3:134)
Do not be rude in speech (3:159)
Be good to others (4:36)
Be dutiful to parents(17:23)
sorted in terms of both the numbers and the serial no stays the same
In order to compare two pair of numbers, you can make comparisons like:
if(suratno[i] < suratno[i-1] || (suratno[i] == suratno[i-1] && ayatno[i] < ayatno[i-1])){
/* swap */
}
Or you can use one expression: expr = suratno * 10000 + ayatno. And make just one comparison:
if(expr[i] < expr[i-1]){
/* swap */
}
Also, I have a few observations about your algorithm/code:
Don't use using namespace std. Specially in big programs, because it can cause obscure bugs (see an example here). Instead use using std::<name> when you want to avoid std::. Ex. using std::string. In general, avoid using namespace xxxx.
I see you did parse the input lines manually, I prefer to use regular expressions, that are much more versatile and powerful, but requires a little learning.
When it's necessary to write an error message, always write to stderr stream cerr in C++.
In the sort algorithm, it's better start in 1 than 0, because the first item doesn't have a previous item to compare with.
Finally the swap can be done with an existent C++ function.
Here is your code reorganized and using regular expressions that I tried to explain as much as possible:
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <vector>
#include <algorithm>
using std::string;
struct Line {
int expr; // Expression used to compare
string text; // Original line without initial number
};
int main() {
std::regex linePattern(
"\\d+" // 1 or more digits
"\\. " // '. ' (dot followed by 1 space)
"(" // begin char group #1
".*" // zero or more chars
"\\(" // '(' (left parenthesis)
"(\\d+)" // char group #2 (suratno: 1+ digits)
":" // ':' (colon)
"(\\d+)" // char group #3 (ayatno: 1+ digits)
"\\)" // ')' (right parenthesis)
")" // end char group #1
);
std::smatch groups; // Regular expression found char groups
std::vector<Line> lines; // Vector to store the readed lines
// Read lines parsing content
std::ifstream fin("text.txt");
if(!fin){
std::cerr << "Cannot open file 'text.txt'! Quitting.\n";
return 1;
}
string line;
while (std::getline(fin, line))
if (std::regex_search(line, groups, linePattern) && groups.size() > 0) {
int suratno = std::stoi(groups[2]);
int ayatno = std::stoi(groups[3]);
int compExpr = suratno * 10000 + ayatno; // assumes ayatno < 10,000
lines.push_back({ compExpr, groups[1] });
}
fin.close();
// sort algorithm (better start in 1)
for (size_t i = 1; i < lines.size(); i++)
for (size_t j = i; j > 0 && lines[j].expr < lines[j - 1].expr; j--)
std::swap(lines[j], lines[j - 1]);
std::ofstream fout("newtext.txt");
if(!fout){
std::cerr << "Cannot open output file 'orderedquranorders.txt'! Quitting.\n";
return 1;
}
for (size_t i = 0; i < lines.size(); i++)
fout << i + 1 << ". " << lines[i].text << std::endl;
fout.close();
std::cout << lines.size() << " orders successfully sorted and written.\n";
return 0;
}
Note: The regular expression is really one string "\\d+\\. (.*\\((\\d+):(\\d+)\\))", I used a C/C++ feature that concatenates strings separated by spaces before compilation, so the compiler sees only one string.
Don't forget to compile with -std=c++11 option.
using namespace std; is considered bad practice and can be dangerous sometimes. Check this
Here is your solution:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
int suratno[100], ayatno[100];
std::string order[100];
char ch;
int count = 0;
int tempInt;
std::string tempStr;
std::ifstream fin;
fin.open("text.txt");
if (!fin)
{
std::cout << "Cannot open file \'text.txt\'! Quitting.\n";
exit(0);
}
else
{
while (fin)
{
fin.get(ch); //gets the numbers
fin.get(ch); //gets .
getline(fin, order[count], '('); //allegedly it removes the delimiter char from stream too
fin >> suratno[count];
fin.get(ch); //gets :
fin >> ayatno[count];
fin.get(ch); //gets )
fin.get(ch); //gets \n
std::cout << count + 1 << "." << order[count] << "(" << suratno[count] << ":" << ayatno[count] << ")\n";
count++;
}
}
fin.close();
std::cout << std::endl;
// sort algorithm (we must sort two times)
for (int i = 0; i < count; i++)
{
for (int j = i; j > 0 && suratno[j] < suratno[j - 1]; j--)
{
tempInt = suratno[j];
suratno[j] = suratno[j - 1];
suratno[j - 1] = tempInt;
tempInt = ayatno[j];
ayatno[j] = ayatno[j - 1];
ayatno[j - 1] = tempInt;
tempStr = order[j];
order[j] = order[j - 1];
order[j - 1] = tempStr;
}
}
for (int i = 0; i < count; i++)
{
for (int j = i; j > 0 && suratno[j] == suratno[j - 1] && ayatno[j] < ayatno[j - 1]; j--)
{
tempInt = ayatno[j];
ayatno[j] = ayatno[j - 1];
ayatno[j - 1] = tempInt;
tempInt = suratno[j];
suratno[j] = suratno[j - 1];
suratno[j - 1] = tempInt;
tempStr = order[j];
order[j] = order[j - 1];
order[j - 1] = tempStr;
}
}
// print the sorted list just to check
for (int i = 0; i < count; i++)
{
std::cout << i + 1 << "." << order[i] << "(" << suratno[i] << ":" << ayatno[i] << ")\n";
}
// write sorted list to output file
std::ofstream fout;
fout.open("newtext.txt");
if (!fout)
{
std::cout << "Cannot open output file\'orderedquranorders.txt\'!Quitting.\n";
exit(0);
}
else
{
for (int i = 0; i < count; i++)
{
fout << i + 1 << "." << order[i] << "(" << suratno[i] << ":" << ayatno[i] << ")\n";
}
}
fout.close();
std::cout << std::endl;
std::cout << count << " orders successfully sorted and written.\n";
return 0;
}
Suppose I have a string exp in the following format:
123+456*789-1011+1213
I want to store all the numbers in vector numbers, and all the operations in vector op.
vector<long long>numbers // {123, 456, 789, 1011, 1213}
vector<char>op // {+, *, -, +}
for (int i = 0; i < exp.size(); i++){
if (exp[i]=="+" || exp[i]=="-" || exp[i]=="*"){
op.push_back(exp[i]);
}else{
...
}
}
How do I store the numbers, and convert them from char to long long?
You will need to parse the input expression to extract the numbers and operator.
There are many ways by which this can be done, however following is my approach.
Traverse through all the character and push the values in Operator vector which is not a digit and replace it with space.
Now extract the numbers from the expression and convert it to numbers and push the values in Number vector.
To know how to split a string you can check the following links:
Split a string - Stack overflow
Split a string - cplusplus.com
Use stol or strtol or string stream to convert string to long value.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main()
{
std::string exp = "123+456*789-1011+1213";
std::vector<long> vecNums;
std::vector<char> vecOper;
for (decltype(exp.size()) i = 0; i < exp.size(); ++i) {
if (!isdigit(exp[i])) {
vecOper.push_back(exp[i]);
exp[i] = ' ';
}
}
std::istringstream iss(exp);
while (iss) {
std::string substr;
long num;
std::getline(iss, substr, ' ');
if (substr.size() != 0) {
// Using strtol function
// num = strtol(substr.c_str(), NULL, 10);
// Using stol function
num = stol(substr);
vecNums.push_back(num);
}
//
// Or use string stream to convert string to long
//
//long num;
//iss >> num;
//vecNums.push_back(num);
}
std::cout << "Numbers: " << std::endl;
for (auto &i : vecNums) {
std::cout << i << " ";
}
std::cout << "\nOperators: " << std::endl;
for (auto &i : vecOper)
std::cout << i << " ";
return 0;
}
If you're going to use iostreams:
void parse_string(const string& s) {
using num_t = long long;
using op_t = char;
istringstream sstr(s);
vector<num_t> numbers;
vector<op_t> ops;
(void)sstr.peek(); //set eofbit if s.empty()
while (!sstr.eof() && !sstr.fail()) {
num_t num;
sstr >> num;
if (!sstr.fail()) {
numbers.push_back(num);
if (!sstr.eof()) {
op_t op;
sstr >> op;
if (!sstr.fail()) {
ops.push_back(op);
}
}
}
}
//assert(ops.size() + 1 == numbers.size());
//copy(begin(numbers), end(numbers), ostream_iterator<num_t>(cout, " "));
//copy(begin(ops), end(ops), ostream_iterator<op_t>(cout, " "));
}
Error checking code as been removed (validate operators are correct, exceptions).
I need to achieve the following:
"4 5 1.3 0 3.1"
This is the input string that I will read from the user, after reading I need to turn this string into a float list according to the [0]th character's size for example the list will be
array[4] = [5.0,1,3,0.0,3.1]
How can I achieve it I tried using getline but didnt work. Thanks in advance.
string line = "4 5 1.3 0 3.1"; // input string
istringstream stream(line); // parser
unsigned count; // how many values
double* values;
if (stream >> count) {
values = new double[count];
for (unsigned ii = 0; ii < count; ++ii) {
stream >> values[ii]; // read one
if (!stream) {
throw std::runtime_error("not enough numbers");
}
}
} else {
throw std::runtime_error("no count at start of line");
}
// do something with values...
delete[] values;
First read the count into an unsigned integer, then loop from 0 to the count, reading into doubles. To read into an array, first allocate one dynamically with the correct size. Better, use a std::vector, which will handle the allocations for you.
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::istringstream ss(line);
size_t num_values = 0;
if (! (ss >> num_values) ) {
std::cerr << "Could not read the integer number of values!\n";
return 1;
}
auto values = std::make_unique<double[]>(num_values);
double tmp;
for (size_t idx = 0; idx < num_values; ++idx) {
if (! (ss >> values[idx])) {
std::cerr << "Could not convert the " << idx << "th value!\n";
return 1;
}
}
// Validate solution: print the contents of the vector
for (size_t idx = 0; idx < num_values; ++idx) {
std::cout << values[idx] << " ";
}
std::cout << "\n";
}
[live example]
This solution uses a dynamically allocated array, and ensures that its memory is correctly cleaned up by wrapping it in a std::unique_ptr, created via a call to std::make_unique.
I wrote this to parse a file with numbers, where the separator was just a space. My goal is to read every number of the file and store it in the corresponding index of the matrix A. So, the first number read, should go to A[0][0], second number to A[0][1] and so on.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
const int N = 5, M = 5;
double A[N*M];
string fname("test_problem.txt");
ifstream file(fname.c_str());
for (int r = 0; r < N; ++r) {
for (int c = 0; c < M; ++c) {
file >> *(A + N*c + r);
}
}
for (int r = 0; r < N; ++r) {
for (int c = 0; c < M; ++c) {
cout << *(A + N*c + r) << " ";
}
cout << "\n";
}
cout << endl;
return 0;
}
Now, I am trying to parse a file like this:
1 ;2 ;3 ;4 ;5
10 ;20 ;30 ;40 ;50
0.1 ;0.2 ;0.3 ;0.4 ;0.5
11 ;21 ;31 ;41 ;5
1 ;2 ;3 ;4 ;534
but it will print (thus read) garbage. What should I do?
EDIT
Here is my attempt in C, which also fails:
FILE* fp = fopen("test_problem.txt", "r");
double v = -1.0;
while (fscanf(fp, "%f ;", &v) == 1) {
std::cout << v << std::endl;
}
-1 will always be printed.
The problem with your C example:
warning: format ‘%f’ expects argument of type ‘float*’, but
argument 3 has type ‘double*’ [-Wformat=]
Always and everywhere, turn on warnings (-Wall -Wextra) and do more error checking.
Anyway, to fscanf into a double you need %lf instead of %f.
Given your input format...
1 ;2 ;3 ;4 ;5
...your code...
for (int c = 0; c < M; ++c) {
file >> *(A + N*c + r);
}
...will "eat" the first numeric value, then choke on the first ; separator. The simplest correction would be...
char expected_semicolon;
for (int c = 0; c < M; ++c) {
if (c) {
file >> expected_semicolon;
assert(expected_semicolon == ';'); // if care + #include <cassert>
}
file >> *(A + N*c + r);
}
For whatever it's worth, to add better error checking I'd suggest...
if (std::ifstream file(fname))
{
...use file stream...
}
else
{
std::cerr << "oops\n";
throw or exit(1);
}
...as a general practice for opening file stream.
For looping getting data, using a support macro to give an assertion-like style works well with streams:
#define CHECK(CONDITION, MESSAGE) \
do { \
if (!(CONDITION)) { \
std::ostringstream oss; \
oss << __FILE__ << ':' << __LINE __ \
<< " CHECK FAILED: " << #CONDITION \
<< "; " << MESSAGE; \
throw std::runtime_error(oss.str()); \
} while (false)
...
for (int c = 0; c < M; ++c) {
if (c)
CHECK(file >> expected_semicolon &&
expected_semicolon == ';',
"values should be separated by semicolons");
CHECK(file >> *(A + N*c + r), "expected a numeric value");
}
For this specific input parsing, for a production system you might want to use getline so you can know where you are in the input...
size_t lineNum = 0;
std::string my_string;
for (int r = 0; r < N; ++r) {
CHECK(getline(file, my_string), "unexpect EOF in input");
++lineNum;
std::istringstream iss(my_string);
for (int c = 0; c < M; ++c) {
if (c)
CHECK(file >> expected_semicolon &&
expected_semicolon == ';',
"unexpected char '" << c
<< "' when semicolon separator needed on line "
<< lineNum);
CHECK(iss >> *(A + N*c + r),
"non numeric value encountered on line " << lineNum);
}
}
}
You should remove semicolon before converting
std::string temp;
file >> temp;
std::replace( temp.begin(), temp.end(), ';', ' ');
*(A + N*c + r) = std::stod( temp );
Why don't you try getline(), which accepts a Delimiter as 3rd argument.
string buffer;
for (int c = 0; c < M; ++c) {
getline(file, buffer, ';');
stringstream tmp(buffer);
tmp>>*(A + N*c + r);
}
getline() will read until the next delimiter or newline or end of file