I have trouble to read in an input from user and convert them into matrix for calculation. For example, with the input = {1 2 3 / 4 5 6}, the program should read in the matrix in the form of
1 2 3
4 5 6
which have 3 cols and 2 rows. What i got so far which does not seem to work:
input.replace(input.begin(), input.end(), '/', ' ');
stringstream ss(input);
string token;
while (getline(ss, token, ' '))
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
int tok = atoi(token.c_str());
(*matrix).setElement(i, j, tok);
}
}
}
So what I'm trying to do is to break the input into token and store them into the matrix using the setElement function which take the number of row, column and the variable that user want to store. What wrong with this code is that the variable of tok doesnt seem to change and keep stuck in 0. Assuming that row and col are knows.
Thanks so much for any help.
Although many simple ways exist to solve the specific problem (and other answer have various good suggestions) let me try to give a more general view of the problem of "formatted input".
There are essentially three kind of problems, here:
at low level you have to do a string to number conversion
at a higher level you have to parse a composite format (understanding rows and line separation)
finally you also have to understand the size of the compound (how many rows and cols?)
this 3 things are not fully independent and the last is needed to know how to store elements (how do you size the matrix?)
Finally there is a 4th problem (that is spread all other the other 3): what to do if the input is "wrong".
These kind of problem are typically afforded in two opposite ways:
Read the data as they come, recognize if the format is matched, and dynamically grow the data structure that have to contain them or...
Read all the data as once as they are (textual form), then analyze the text to figure out how many elements it has, then isolate the "chunks" and do the conversions.
Point 2. requires good string manipulations, but also requires the ability to know how the input is long (what happens if one of the separating spaces is a new-line? the idea the everything is got with a getline fails in those cases)
Point 1 requires a Matrix class that is capable to grow as you read or a temporary dynamic structure (like and std container) in which you can place what you read before sending it into the appropriate place.
Since I don't know how your matrix works, let me keep a temporary vector and counters to store lines.
#include <vector>
#include <iostream>
#include <cassert>
class readmatrix
{
std::vector<int> data; //storage
size_t rows, cols; //the counted rows and columns
size_t col; //the counting cols in a current row
Matrix& mtx; //refer to the matrix that has to be read
public:
// just keep the reference to the destination
readmatrix(Matrix& m) :data(), rows(), cols(), cols(), mtx(m)
{}
// make this class a istream-->istream functor and let it be usable as a stream
// manipulator: input >> readmatrix(yourmatrix)
std::istream& operator()(std::istream& s)
{
if(s) //if we can read
{
char c=0:
s >> c; //trim spaces and get a char.
if(c!='{') //not an open brace
{ s.setstate(s.failbit); return s; } //report the format failure
while(s) //loop on rows (will break when the '}' will be found)
{
col=0;
while(s) //loop on cols (will break when the '/' or '}' will be found)
{
c=0; s >> c;
if(c=='/' || c=='}') //row finished?
{
if(!cols) cols=col; //got first row length
else if(cols != col) //it appears rows have different length
{ s.setstate(s.failbit); return s; } //report the format failure
if(c!='/') s.unget(); //push the char back for later
break; //row finished
}
s.unget(); //pushthe "not /" char back
int x; s >> x; //get an integer
if(!s) return s; //failed to read an integer!
++col; data.push_back(x); //save the read data
}
++rows; //got an entire row
c=0; s >> c;
if(c == '}') break; //finished the rows
else s.unget(); //push back the char: next row begin
}
}
//now, if read was successful,
// we can dispatch the data into the final destination
if(s)
{
mtx.setsize(rows,cols); // I assume you can set the matrix size this way
auto it = data.begin(); //will scan the inner vector
for(size_t r=0; r<rows; ++r) for(size_t c=0; c<cols; ++c, ++it)
mtx(r,c) = *it; //place the data
assert(it == data.end()); //this must be true if counting have gone right
}
return s;
}
};
Now you can read the matrix as
input >> readmatrix(matrix);
You will notice at this point that there are certain recurring patterns in the code: this is typical in one-pass parses, and those patterns can be grouped to form sub-parsers. If you do it generically you -in fact- will rewrite boost::spirit.
Of course some adaption can be done depending on how your matrix works (has it fixed sizes??), or what to do if rows sizes don't match (partial column filling ??)
You can even add a formatted input operator like
std::istream& operator>>(std::istream& s, Matrix& m)
{ return s >> readmatrix(m); }
so that you can just do
input >> matrix;
You are trying to operate on each cell of the matrix for each char read in the input!
You have to take one char for each cell, not multiple.
Splitting a string in tokens can be done by using the following function.
Please don't be shocked that the following code isn't runnable, this is due to the missing matrix class.
Try the following:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
using namespace std;
void split(const string& str, char delimiter, vector<string>& result) {
string::size_type i = 0;
string::size_type delimOcc = str.find(delimiter);
while (delimOcc != string::npos) {
result.push_back(str.substr(i, delimOcc-i));
i = ++delimOcc;
delimOcc = str.find(delimiter, delimOcc);
if (delimOcc == string::npos) {
result.push_back(str.substr(i, str.length()));
}
}
}
int main()
{
std::string input = "1 2 3 / 4 5 6";
vector<string> rows;
split(input, '/', rows);
for(int i = 0; i < rows.size(); i++) {
vector<string> cols;
split(rows[i], ' ', cols);
for(int j = 0; j < cols.size(); j++) {
if(cols[j][0] != '\0'){
int tok = stoi(cols[j]);
(*matrix).setElement(i, j, tok);
cout << tok << " - " << i << " - " << j << endl;
}
else {
if(j == 0) j--;
}
}
}
return 0;
}
If you know the size of the matrix on forehand you actually don't need getline, you should read int by int. (untested code)
input.replace(input.begin(), input.end(), '/', '\n');
stringstream ss(input);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
int tok;
ss >> tok;
(*matrix).setElement(i, j, tok);
}
}
Related
I have an array that reads data from a file, the data is binary digits such as 010011001001 and many others so the data are strings which I read in to my 2d array but I am stuck on comparing each value of the array to 0. Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string myArr[5000][12];
int i = 0, zeroCount = 0, oneCount = 0;
ifstream inFile;
inFile.open("Day3.txt");
while(!inFile.eof())
{
for(int i = 0; i < 5000; i++)
{
for(int j = 0; j < 12; j++)
{
inFile >> myArr[i][j];
j++;
}
i++;
}
}
for(int j = 0; j < 12; j++)
{
for(int i = 0; i < 5000; i++)
{
if(myArr[i][j].compare("0") == 0)
{
zeroCount++;
}
else
{
oneCount++;
}
i++;
}
if(zeroCount > oneCount)
{
cout << "Gamma is zero for column " << i << endl;
}
else
{
cout << "Gamma is One for column " << i << endl;
}
j++;
}
}
some input from the text file:
010110011101
101100111000
100100000011
111000010001
001100010011
010000111100
Thank you for editing you question and providing more information. Now, we can help you. You have 2 major misunderstandings.
How does a for loop work?
What is a std::string in C++
Let us start with the for loop. You find an explanation in the CPP reference here. Or, you could look also at the tutorial shown here.
The for loop has basically 3 parts: for (part1; part2; part3). All are optional, you can use them, but no need to use them.
part1 is the init-statement. Here you can declare/define/initialize a variable. In your case it is int i = 0. You define a variable of data type int and initialize it with a value of 0
part2 is the condition. The loop will run, until the condition becomes false. The condition will be check at the beginning of the loop.
part3 is the so called iteration-expression. The term is a little bit misguiding. It is basically a statement that is executed at the end of the loop, before the next loop run will be executed and before the condition is checked again.
In Pseudo code it is something like this:
{
init-statement
while ( condition ) {
statement
iteration-expression ;
}
}
which means for the part of your code for(int j = 0; j < 12; j++)
{
int j = 0; // init-statement
while ( j < 12 ) { // while ( condition ) {
inFile >> myArr[i][j]; // Your loop statements
j++; // Your loop statements PROBLEM
j++; // iteration-expression from the for loop
}
}
And now you see the problem. You unfortunately increment 'j' twice. You do not need to do that. The last part3 of the for loop does this for you already.
So please delete the duplicated increment statements.
Next, the std::string
A string is, as its names says, a string of characters, or in the context of programming languages, an array of characters.
In C we used to write actually char[42] = "abc";. So using really a array of characters. The problem was always the fixed length of such a string. Here for example 42. In such an array you could store only 41 characters. If the string would be longer, then it could not work.
The inventors of C++ solved this problem. They created a dynamic character array, an array that can grow, if needed. They called this thing std::string. It does not have a predefined length. It will grow as needed.
Therefore, writing string myArr[5000][12]; shows that you did not fully understand this concept. You do not need [12], becuase the string can hold the 12 characters already. So, you can delete it. They characters will implicitely be there. And if you write inFile >> myString then the extractor operator >> will read characters from the stream until the next space and then store it in your myString variable, regardless how long the string is.
Please read this tutorial about strings.
That is a big advantage over the C-Style strings.
Then your code could look like:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string myArr[5000];
int zeroCount = 0, oneCount = 0;
ifstream inFile;
inFile.open("Day3.txt");
while (!inFile.eof())
{
for (int i = 0; i < 5000; i++)
{
inFile >> myArr[i];
}
}
for (int i = 0; i < 5000; i++)
{
zeroCount = 0; oneCount = 0;
for (int j = 0; j < 12; j++)
{
if (myArr[i][j]== '0')
{
zeroCount++;
}
else
{
oneCount++;
}
}
if (zeroCount > oneCount)
{
cout << "Gamma is zero for column " << i << endl;
}
else
{
cout << "Gamma is One for column " << i << endl;
}
}
}
But there is more. You use the magic number 5000 for your array of strings. This you do, because you think that 5000 is always big enough to hold all strings. But what, if not? If you have more than 5000 strings in your source file, then your code will crash.
Similar to the string problem for character arrays, we have also a array for any kind of data in C++, that can dynamically grow as needed. It is called std::vector and you can read about it here. A tutorial can be found here.
With that you can get rid of any C-Style array at all. But please continue to study the language C++ further and you will understand more and more.
Ther are more subtle problems in your code like while(!inFile.eof()), but this should be solved later.
I hope I could help
Basically, I'm reading a file and trying to store the data in a 2D, for the differentiation between rows and columns I use the logic below:
int rows=0,column=0;
char arr[50][50];
while(my_file.eof()==0){
my_file.get(ch);
if(ch=='\n'){
rows++;
}
arr[rows][column]=ch;
column++;
}
for(int j=0;j<rows;j++){
for(int k=0;k<column;k++){
cout<<arr[j][k];}
}
But the when I run It shows the following output: https://i.stack.imgur.com/XzhST.png
And the text file data is:
I am going to school
hi!
Hello
guide me a bit...
Hmm, a 2D char array can indeed be used to store an number of lines, but you should control that you never try to store more than 50 characters for a single line, and that you never try to ouput more characters for a line than what it initially contained.
Here is a minimal fix of your code:
int rows = 0, column = 0;
char arr[50][50] = { {0 } }; // ensure the array is initialized with '\0' chars
for (;;) {
my_file.get(ch);
if (!my_file) break; // eof shall be tested AFTER a read operation
if (ch == '\n') {
rows++;
if (rows == 50) break; // no more than 50 lines
column = 0; // reset column index for next line
}
else if (column < 50) { // no more than 50 columns
arr[rows][column] = ch;
column++;
}
}
for (int j = 0; j < rows; j++) {
for (int k = 0; k < 50; k++) {
if (arr[j][k] == 0) break; // stop on end of line
std::cout << arr[j][k];
}
std::cout << '\n'; // and display the end of line
}
And as you have been said this is rather C-ish... I assume it is only for learning how 2D arrays can work.
As pointed out in comments, you'd be much better off using a std::vectorstd::string to store the strings.
But, this looks like a homework assignment to read then print each byte separately, so let's have a look... I'll add one of the ways this is usually done at the end of this post.
Your output looks like this:
It looks like you are displaying characters beyond the bondary of the strings, or that your strings are not null terminated... Turns out it's both.
Your code:
int rows = 0, column = 0;
char arr[50][50]; // <-- your array is not initialized, while that is not
// a big issue, filling the array with zeroes is easy:
// char arr[50][50] = {};
while (my_file.eof() == 0) {
my_file.get(ch);
if (ch == '\n') {
rows++; // <-- you pass to the next string, but do not put a
// null character to properly terminate your strings
// while this could have been avoided by initializing
// the array, it's best to do it explicitely.
// replace above line contents by:
arr[row][column] = '\0';
if (++row >= 50) // consider using named constants for the size of your array.
break; // No use keeping on reading strings if there is no
// more room to store them
}
arr[rows][column] = ch; // <-- I suspect a bunch un undefined stuff will
// start happening when column >= 50
column++;
// Try replacing above code with:
if (column < 50) // consider using named constants for the size of your array.
arr[rows][column++] = ch;
}
// make sure the last string is null terminated.
if (row < 50 && column < 50)
arr[row][column] = '\0';
// note that strings that are 50 bytes long are NOT null terminated.
// that's important to keep in mind, and only workss because we'll print
// byte by byte.
// your original print routine prints out all characters in the array, even
// stuff that was not in the original file...
for (int j = 0; j < rows; ++j){
for (int k=0 ; k < column; ++k){ // <-- you need to check for a null
// terminating character here...
// also, column is the length of the last
// string in the array. This is not a very
// useful value for displaying any other
// strings, is it?
// try this:
for (int k = 0; k < 50 && arr[j][k] != '\0'; ++k)
cout << arr[j][k];
}
cout << '\n'; // insert a newline after each string.
}
As you can tell, this is overly complex for doing a very common operation... Here's a more concise way of doing the same thing:
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
int main()
{
std::vector<std::string> arr;
std::ifstream ifs("testfile.txt");
while (ifs && !ifs.eof())
{
std::string str;
std::getline(ifs, str);
arr.push_back(str);
}
for (size_t i = 0; i < arr.size(); ++i)
std::cout << arr[i] << '\n';
return 0;
}
Because you haven't compile the array yet
char arr[50][50];
for (int r = 0; r < 50; r++){
for (int c = 0; c < 50; c++){
arr[r][c] = ' ';}
}
You are given an n*m grid which contains lower case English letters. How many times does the phrase "saba" appear horizontally, vertically, and diagonally in the grid?
Counting horizontally, vertically and diagonally.
#include<iostream>
#include <vector>
#include <string>
using namespace std;
int TotalCount(vector<string> Str, int ItemCount)
{
string Text = "saba";
string VerticalString = "";
string DiagonalOneString = "";
string DiagonalTwoString = "";
int count = 0;
for (int i = 0; i < ItemCount; ++i)
{
string& currentRow = Str[i];
VerticalString = VerticalString.append(¤tRow.at(0));
DiagonalOneString = DiagonalOneString.append(¤tRow.at(i));
DiagonalTwoString =
DiagonalTwoString.append(¤tRow.at(currentRow.length() - 1 - i));
if ((currentRow.find(Text) != string::npos) || (VerticalString.find(Text) != string::npos) || (DiagonalOneString.find(Text) != string::npos) || (DiagonalTwoString.find(Text) != string::npos))
{
count++;
}
}
return count;
}
int main()
{
int total = 0;
int row;
cin >> row;
vector<string> rows;
// read each row and append to the "rows" vector
for (int r = 0; r < row; r++)
{
string line;
cin >> line;
rows.push_back(line);
}
cout << TotalCount(rows, row);
return 0;
}
Input format
First line: Two integer n and m, where n denotes (1 <= n,m <= 100) the number of rows and m denotes the number of columns in the grid
Next n lines: Each line must contain a string of length m which contains lower-case English letters only
Sample Input
5 5
safer
amjad
babol
aaron
songs
Expected Output
2
It seems like VerticalString copies the whole string instead of copying the character at the specified position. I am not getting the expected count. Can please someone let me know why the count is coming wrong?
When your vertical string is saba, count will increment. But count will increment again when your vertical string is sabas, for the same hit.
Also, you probably meant to search diagonals besides just the two between corners. Looking at only 2 diagonals allows for the possibility of overlooking valid hits. And reading both directions is probably required.
My recommendation would be to break down the problem into counting hits from each horizontal row, counting hits from each vertical row (could transpose the matrix and re-use the first function), counting diagonals (northeast to southwest), and finally counting diagonals (northwest to southeast). I.e., dedicate a new function for each of them, and sum the results.
Printing strings you're testing would greatly help you with debugging, too.
I'm trying to solve this problem from an online judge (Codeforces):
One day Deivis came across two Vectors of integers A and B, and wondered, could it be possible to form the number X by adding an element of A to another element of B?
More formally, it is possible to choose two indexes i and j such that Ai + Bj = x?
Input
The first entry line is two integers n and x. The second line contains n numbers, the vector A. The third and last line contains n numbers, vector B.
Output
Print 1 if it is possible to form the number x from a sum of one element of each vector, and 0 otherwise."
My problem is that I can not fill in the second vector, when the program runs on the site it fills the vector with zeros. I am using C ++, here's my code:
#include <bits/stdc++.h>
using namespace std;
#define MAX 10
int main()
{
int n, x, i = 0, j = 0, resp = 0, sum;
vector<int> vetA(MAX), vetB(MAX);
cin >> n >> x;
while (scanf("%d", &vetA[i]) == 1)
i++;
while (scanf("%d", &vetB[j]) == 1)
j++;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
sum = vetA[i] + vetB[j];
if (sum == x)
{
resp = 1;
goto END;
}
}
}
END: printf("%d", resp);
return 0;
}
I try to use getchar() after each while loop, but seems that on the site it does not do data capture like on a keyboard, and so the second vector isn't receiving any data. I've also tried to capture data as a std::string but that doesn't work.
Can someone help me?
Here are some hints/examples to compare your program to:
#include <iostream> //Include each standard library seperately
#include <vector> //#include <bits/stdc++.h> is bad practice
// Only declare variables as they are used.
int n; // Better coding practice is one variable per line.
int x; // Competitions shouldn't care how many lines.
if (!(std::cin >> n >> x)) //This is basically the same as cin.fail()
{
std::cerr << "Error inputting data.\n";
return 1;
}
// Now create the vectors, after the size has read in.
std::vector<int> vetA(n);
std::vector<int> vetB(n);
// The number of elements is known, so use a "for" loop.
for (size_t i = 0; i < n; ++i)
{
std::cin >> vetA[i];
}
for (size_t i = 0; i < x; ++i)
{
std::cin >> vetB[i];
}
You should add in some error handling because your program will be given some invalid inputs.
The inputs and vector sizes are examples since you didn't specify the input format in your Post.
This question already has answers here:
Parse (split) a string in C++ using string delimiter (standard C++)
(33 answers)
How do I iterate over the words of a string?
(84 answers)
Closed 6 years ago.
So I am given a file with ten matrices, and I would like to read from file these matrices and save them into vectors/arrays, where each matrix is stored into either a vector or an array. However, the format of these matrices makes it hard for me to read the data(I'm not good with reading from input file).
the file has the following format. Elements of each matrix are separated by "," . Each row is separated by ";", and each matrix is separated by "|". For example three 2 by 2 matrices are as follows.
1,2;3,4|0,1;1,0|5,3;3,1|
And I just want to save matrices into three different vectors, but I am not sure how to do this.
I tried
while(getline(inFile,line)){
stringstream linestream(line);
string value;
while(getline(linestream, value, ','){
//save into vector
}
}
But this is obviously very crude, and only seperates data by comma. Is there a way to separate the data with multiple delimiters?
Thank you!
string line;
while(getline(infile, line, '|'))
{
stringstream rowstream(line);
string row;
while(getline(rowstream, row, ';'))
{
stringstream elementstream(row);
string element;
while(getline(elementstream, element, ','))
{
cout << element << endl;
}
}
}
Using above code you can build the logic to store individual element as you like.
I use this own function to split a string to a vector of strings :
/**
* \brief Split a string in substrings
* \param sep Symbol separating the parts
* \param str String to be splitted
* \return Vector containing the splitted parts
* \pre The separator can not be 0
* \details Example :
* \code
* std::string str = "abc.def.ghi..jkl.";
* std::vector<std::string> split_str = split('.', str); // the vector is ["abc", "def", "ghi", "", "jkl", ""]
* \endcode
*/
std::vector<std::string> split(char sep, const std::string& str);
std::vector<std::string> split(char sep, const std::string& str)
{
assert(sep != 0 && "PRE: the separator is null");
std::vector<std::string> s;
unsigned long int i = 0;
for(unsigned long int j = 0; j < str.length(); ++j)
{
if(str[j] == sep)
{
s.push_back(str.substr(i, j - i));
i = j + 1;
}
}
s.push_back(str.substr(i, str.size() - i));
return s;
}
Then, expecting you have a class Matrix, you can do something like :
std::string matrices_str;
std::ifstream matrix_file(matrix_file_name.c_str());
matrix_file >> matrices_str;
const std::vector<std::string> matrices = split('|', matrices_str);
std::vector<Matrix<double> > M(matrices.size());
for(unsigned long int i = 0; i < matrices.size(); ++i)
{
const std::string& matrix = matrices[i];
const std::vector<std::string> rows = split(';', matrix);
for(unsigned long int j = 0; j < rows.size(); ++j)
{
const std::string& row = matrix[i];
const std::vector<std::string> elements = split(',', row);
for(unsigned long int k = 0; k < elements.size(); ++k)
{
const std::string& element = elements[k];
if(j == 0 && k == 0)
M[i].resize(rows.size(), elements.size());
std::istringstream iss(element);
iss >> M[i](j,k);
}
}
}
Or, compressed code :
std::string matrices_str;
std::ifstream matrix_file(matrix_file_name.c_str());
matrix_file >> matrices_str;
const std::vector<std::string> matrices = split('|', matrices_str);
std::vector<Matrix<double> > M(matrices.size());
for(unsigned long int i = 0; i < matrices.size(); ++i)
{
const std::vector<std::string> rows = split(';', matrices[i]);
for(unsigned long int j = 0; j < rows.size(); ++j)
{
const std::vector<std::string> elements = split(',', matrix[i]);
for(unsigned long int k = 0; k < elements.size(); ++k)
{
if(j == 0 && k == 0)
M[i].resize(rows.size(), elements[k].size());
std::istringstream iss(elements[k]);
iss >> M[i](j,k);
}
}
}
You can use finite state machine concept. You need define states for each step.
Read one char and then decide what it is (number or delimiter).
Here is concept how you could do it.
For more reading check this on internet. text parsing, finite state machine, lexical analyzer, formal grammar
enum State
{
DECIMAL_NUMBER,
COMMA_D,
SEMICOLON_D,
PIPE_D,
ERROR_STATE,
};
char GetChar()
{
// implement proper reading from file
static char* input = "1,2;3,4|0,1;1,0|5,3;3,1|";
static int index = 0;
return input[index++];
}
State GetState(char c)
{
if ( isdigit(c) )
{
return DECIMAL_NUMBER;
}
else if ( c == ',' )
{
return COMMA_D;
}
else if ( c == ';' )
{
return SEMICOLON_D;
}
else if ( c == '|' )
{
return PIPE_D;
}
return ERROR_STATE;
}
int main(char* argv[], int argc)
{
char c;
while ( c = GetChar() )
{
State s = GetState(c);
switch ( c )
{
case DECIMAL_NUMBER:
// read numbers
break;
case COMMA_D:
// append into row
break;
case SEMICOLON_D:
// next row
break;
case PIPE_D:
// finish one matrix
break;
case ERROR_STATE:
// syntax error
break;
default:
break;
}
}
return 0;
}
The example you have actually maps to a very simple byte machine.
Start with a zeroed matrix and something that keeps track where in the matrix you're writing. Read one character at a time. If the character is a digit, multiply the current number in the matrix by 10 and add the digit to it, if the character is a comma, advance to the next number in the row, if the character is a semi-colon go to the next row, if the character is a pipe, start a new matrix.
You might not want to do it exactly this way if the numbers are floating point. I'd save them in a buffer and use a standard method of parsing floating point numbers. But other than that you don't really need to keep much complex state or build a large parser. You might want to add error handling at a later stage, but even there the error handling is pretty trivial and only depends on the current character you're scanning.