Putting text file content into a 2D array - c++

I'm trying to read in a text file that is 200 x 1000 of numbers into an array. Each number is separated by a tab. I thought using a 2D array would be good for this situation since it would allow me to distinguish between the individual rows. Being able to distinguish between the individual rows is important in this situation which is why I wanted to do it in this manner. Right now I have the following:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream file("text.txt");
if(file.is_open())
{
string myArray[1000];
for(int i = 0; i < 1000; ++i)
{
file >> myArray[i];
cout << myArray[i] << endl;
}
}
}
Which currently scans the first row of numbers into the array and then prints it out. I wanted to have a 2D array that scans each individual row into the array but keeps them separate. This means the content of row 1 is separate from the content of row 2. I figured a 2D array would do this. I am a bit stuck on this part. I attempted to make a 2D array through the use of a nested for loop but when I tried to copy the values over into the array things started to go wrong. The order was incorrect and the rows were not separated. I am coding this in C++. If someone could help me understand how to import a text document like the one I described and send all that information to a 2D array I would greatly appreciate it. Thanks.

You can use a stringstream to extract the numbers from each row. Also, you don't need to have an array of strings. You can just use one string.
int main()
{
ifstream file("text.txt");
if(file.is_open())
{
for(int i = 0; i < 1000; ++i)
{
string row;
if ( std::getline(file, row) )
{
std::istringstream istr(row);
int number;
while ( istr >> number )
{
// Add the number to a container.
// Or print it to stdout.
cout << number << "\t";
}
cout << endl;
}
}
}
}

If your dimensions change, you use the following code. Note that you can use std::copy to copy from a std::stringstream into a std::vector:
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
int main()
{
std::string input =
"11 12\n"
"21 22\n"
"31 32\n"
"41 42\n"
;
std::stringstream file(input);
std::string temp;
while (std::getline(file, temp)) {
std::stringstream line(temp);
std::vector<std::string> v;
std::copy(
std::istream_iterator<std::string>(line),
std::istream_iterator<std::string>(),
std::back_inserter(v));
for (auto x: v)
std::cout << x << " ";
std::cout << "\n";
}
}

Related

why is this code not giving the desired output?

#include <sstream>
#include <vector>
#include <iostream>
using namespace std;
vector<int> parseInts(string str) {
istringstream ss(str);
vector<int> integ;
int val;
while(ss){
if(ss>>val){
integ.push_back(val);
}
}
return integ;
}
vector<int> parseInts2(string str)
{
vector<int> vec;
stringstream ss(str);
char ch;
int temp;
while(ss)
{
ss>>temp>>ch; >> operator
vec.push_back(temp);
}
return vec;
}
int main() {
string str;
cin >> str;
vector<int> integers = parseInts(str);
for(int i = 0; i < integers.size(); i++) {
cout << integers[i] << "\n";
}
return 0;
}
i want to create a stream,to a string,read integers to the stream from the string and insert it in a vector and display its elements while the output is displaying nothing.what is wrong with the code?
EDIT
basically the question ask inputs in the form of integers that are separated by commas and asks us to print the integers after parsing it. i find no significant difference between the 2 functions but parseInt2 still works(while calling the function in main,of course instead of parseInt). Why?
I fear that your question will be closed by people on SO.
But let me give you the answer.
Basically everything set already in the comments. Why not in an answer? I do not know.
Before you can read something from an std::istringstream, you need to put something in it. You need to initialize it. That is usually done by using its constructor:
istringstream ss(str);
In main, you have the problem, that you read only one value from std::cin with cin >> str;. You want to use std::getline instead, which reads a complete line. And not only "something" up to the next space. So
getline(cin, str);
will help you further.
In modern C++, with keeping the std::istringstream approach, you would probably write
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
int main() {
// Read a line and check, if that worked
if (std::string str; std::getline(std::cin, str)) {
// Create and initialize a std::istringstream
std::istringstream iss(str);
// Define a variable integers, use its range constructor with iterators
std::vector integers(std::istream_iterator<int>(iss), {});
// Range based for loop
for (const int& i : integers) {
std::cout << i << "\n";
}
}
return 0;
}
That will save the subfunction.
EDIT:
OK, you want to read csv and you must use ">>".
If you want to read data separated by comma from a stream, then you need to extract:
an integer value from the stream
then a comma
then a integer
then a comma
then a integer
. . .
The extractor operator, or the functionality behind it, will always extract characters from a stream and convert it to a requested type (e.g. an integer), until it reaches a space or the conversion can not be continued any longer (for example, a "," is a separator).
That is the reason, why your 2nd function works.
It is important that you alwys check the status of the extraction operation. In the below example you will see that, at the end of the string, we try to read a comma, where there is none. The extraction fails, but we do not care. We ignore it by intent. To understand the functionality better, please see.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main() {
// Source or test data. We put it directly into the stream;
std::istringstream ss{ "1,2,3, 4 , 5,6" };
std::vector<int> integers{};
char comma{};
int integer{};
while (ss) {
// Read integer and check, if it could be read
if (ss >> integer) {
integers.push_back(integer);
std::cout << "Read Integer " << integer << "\n";
}
else
std::cerr << "Error: Could not read integer\n";
// Now read the comma
if (ss && (ss >> comma))
std::cout << "Read Comma: " << comma << "\n";
else
std::cerr << "Error: Could not read comma\n";
}
// SHow all values
for (const int i : integers) std::cout << i << "\n";
return 0;
}
If you have questions, I am happy to answer.

stock data from file into arrays c++

I have this specific code to read integers from a text file:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
bool contains_number(const string &c);
int main()
{
int from[50], to[50];
int count = 0;
{
string line1[50];
ifstream myfile("test.txt");
int a = 0;
if (!myfile)
{
cout << "Error opening output file" << endl;
}
while (!myfile.eof())
{
getline(myfile, line1[a]);
if (contains_number(line1[a]))
{
count += 1;
myfile >> from[a];
myfile >> to[a];
//cout << "from:" << from[a] << "\n";
//cout << "to:" << to[a] << "\n";
}
}
}
return 0;
}
bool contains_number(const string &c)
{
return (c.find_first_of("1:50") != string::npos);
}
I need to stock these values of from[] and to[] in 2 arrays to use them n another function, I tried to create 2 arrays in a simple way and affect the values for example:
int x[], y[];
myfile >> from[a];
for(int i=0; i<50;i++)
{
x[i] = from[i];
}
but it doesn't work. It seems that this way is only to read and display and a value in from will be deleted once another value comes.
Any help?
Thanks.
You're not incrementing your array index a in your loop. This results in line[0], to[0] and from[0] to be overwritten for every line in the file where contains_number returns true.
There is no reason for you to save your lines into memory. You can just process your lines as you go through the file (i.e. create a string line variable in your while loop).
Make sure you properly close your file handle.
Aside from that you should check your index bounds in the loop (a < 50), else you might be writing out of bounds of your arrays if your file has more numbers than 50.
A better solution yet would be to use vectors instead of arrays, especially if your file may contain any number of numbers.

Read a file of strings with quotes and commas into string array

Let's say I have a file of names such as:
"erica","bosley","bob","david","janice"
That is, quotes around each name, each name separated by a comma with no space in between.
I want to read these into an array of strings, but can't seem to find the ignore/get/getline/whatever combo to work. I imagine this is a common problem but I'm trying to get better at file I/O and don't know much yet. Here's a basic version that just reads in the entire file as one string (NOT what I want, obviously):
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
fstream iFile("names.txt", ios::in);
string names[5];
int index = 0;
while(iFile)
{
iFile >> names[index];
index++;
}
for(int i = 0; i < 5; i++)
{
cout << "names[" << i << "]: " << names[i] << endl;
}
Output:
names[0]: "erica","bosley","bob","david","janice"
names[1]:
names[2]:
names[3]:
names[4]:
Also, I understand why it all gets read as a single string, but then why are the remaining elements not filled with garbage?
To be clear, I want the output to look like:
names[0]: erica
names[1]: bosley
names[2]: bob
names[3]: david
names[4]: janice
The easiest way to handle this:
Read the entire file and place it into a string, Here is an example of how to do it.
Split the string that you got from number 1. Here is an example of how to do that.
Stream extraction delimits by a space. Therefore the entire file gets read as one string. What you want instead is to split the string by commas.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <sstream>
fstream iFile("names.txt", ios::in);
string file;
iFile >> file;
std::istringstream ss(file);
std::string token;
std::vector<std::string> names;
while(std::getline(ss, token, ',')) {
names.push_back(token);
}
To remove the quotes, use this code:
for (unsigned int i = 0; i < names.size(); i++) {
auto it = std::remove_if(names[i].begin(), names[i].end(), [&] (char c) { return c == '"'; });
names[i] = std::string(names[i].begin(), it);
}
remove_if returns the end iterator for the transformed string, which is why you construct the new string with (s.begin(), it).
Then output it:
for (unsigned int i = 0; i < names.size(); i++) {
std::cout << "names["<<i<<"]: " << names[i] << std::endl;
}
Live Example

Reading a list of numbers and sorting C++

I'm trying to read a list of numbers from a file and sort them by reading them into an array and then sorting the contents of the array. But I'm getting
error:incompatible types in assignment of 'std::basic_ostream<char, std::char_traits<char> >' to 'int [1]'
I'm fairly new to programming and this is my first time working with C++
Can anyone tell me how to write the list of numbers to an array so that I can sort them?
Here is what I have:
#include <fstream>
#include <iostream>
#include <iomanip>
#define ANYSIZE_ARRAY 1
using std::cout;
using std::endl;
int main()
{
const char* filename = "test.txt";
std::ifstream inputFile(filename);
int numbers[ANYSIZE_ARRAY];
int i, key;
// Make sure the file exists
if(!inputFile)
{
cout << endl << "The File is corrupt or does not exist. " << filename;
return 1;
}
long n = 0;
while(!inputFile.eof())
{
inputFile >> n;
numbers = cout << std::setw(10) << n;
}
for(int j=1;j<5;j++)
{
i=j-1;
key=numbers[j];
while(i>=0 && numbers[i]>key)
{
numbers[i+1]=numbers[i];
i--;
}
numbers[i+1]=key;
}
//Display sorted array
cout<<endl<<"Sorted Array\t";
for(i=0;i<5;i++)
cout<<numbers[i]<<"\t";
cout<<endl;
}
The line causing the error is:
numbers = cout << std::setw(10) << n;
I'm not quite sure what you're trying to do here, it looks like you just want to print it in which case the numbers = isn't needed.
The structure of your loop to read all the data is problematic also. The line: while (!inputFile.eof()) isn't idiomatic C++ and won't do what you hope. See here for a discussion on that issue (and here).
For reference you can do this quite simply with less work by using std::sort
#include <iterator>
#include <algorithm>
#include <vector>
#include <fstream>
#include <iostream>
int main() {
std::ifstream in("test.txt");
// Skip checking it
std::vector<int> numbers;
// Read all the ints from in:
std::copy(std::istream_iterator<int>(in), std::istream_iterator<int>(),
std::back_inserter(numbers));
// Sort the vector:
std::sort(numbers.begin(), numbers.end());
// Print the vector with tab separators:
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<int>(std::cout, "\t"));
std::cout << std::endl;
}
This program also uses a std::vector instead of an array to abstract the "how big should my array be?" problem (which your example looked to have a possible problem problem with).
Here is what you need to do to get your program to work:
Change ANYSIZE_ARRAY to 5
Where you read the numbers, replace the while with this:
long n = 0;
i=0;
while(!inputFile.eof())
{
inputFile >> n;
cout << std::setw(10) << n;
numbers[i]=n;
i++;
}
This way, you will create an array which can hold 5 numbers, and you will read the numbers into that array. I used 5 because I saw that you were using the same number in the sorting algorithm, so I assumed that you only have to read 5 numbers. This is a bad thing, because your program will only work with 5 numbers.
If you need it to work with a variable amount of numbers, you can use a std::vector<long> to store the numbers. You can create a vector, and then use push_back() to add numbers to it. The vector will resize automatically and will hold as many numbers as you put in it. Then you can replace the 5s in your code with the vector's size() method.
You were getting your original error because this line doesn't make sense:
numbers = cout << std::setw(10) << n;
C++ views that line as if you are trying to print out the number to the stdout stream (which is in our case the console, the screen), and then assigning that stream to the "numbers" array. You cannot assign an output stream to an integer array (hence the error cannot convert from ostream to int[1]).
First, you should not assign an outstream variable to an int.
Second, n is long type and numbers is an integer array. There is type-unsafety.
Third, you should pre-allocate array size.
Forth, you can directly use sort() in STL function to do the sorting.
Try the following code:
#include <fstream>
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
#define ANYSIZE_ARRAY 5
int main()
{
const char* filename = "test.txt";
std::ifstream inputFile(filename);
int numbers[ANYSIZE_ARRAY];
int i, key;
// Make sure the file exists
if(!inputFile)
{
cout << endl << "The File is corrupt or does not exist. " << filename;
return 1;
}
int n = 0;
i = 0;
while(!inputFile.eof())
{
inputFile >> n;
cout << std::setw(10) << n;
numbers[i++] = n;
}
sort(numbers, numbers + ANYSIZE_ARRAY);
//Display sorted array
cout<<endl<<"Sorted Array\t";
for(i=0; i<ANYSIZE_ARRAY; i++)
cout<<numbers[i]<<"\t";
cout<<endl;
}

How to read space and newline separated integers into a 2D array in C++?

I have a .txt file of numbers (in this case all less than 100) separated by spaces, in rows separated by new lines. Something like this:
41 53 07 91 44
52 17 13 03 21
I would like to read these numbers into a 2d array, exactly as they appear, so that spaces separate columns of the array, and new lines separate rows.
I can get it to read the lines in as strings, but then I'm having trouble separating out individual numbers, and getting it to treat them as integers.
Try this:
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
int main()
{
// The result of the read is placed in here
// In C++, we use a vector like an array but vectors can dynamically grow
// as required when we get more data.
std::vector<std::vector<int> > data;
// Replace 'Plop' with your file name.
std::ifstream file("Plop");
std::string line;
// Read one line at a time into the variable line:
while(std::getline(file, line))
{
std::vector<int> lineData;
std::stringstream lineStream(line);
int value;
// Read an integer at a time from the line
while(lineStream >> value)
{
// Add the integers from a line to a 1D array (vector)
lineData.push_back(value);
}
// When all the integers have been read, add the 1D array
// into a 2D array (as one line in the 2D array)
data.push_back(lineData);
}
}
Ok, the "exactly as they appear" requirement means that you need a ragged array, in case different number of columns appear in different rows. I would use std::vector< std::vector<long> >. Each contained vector corresponds to one row.
So, each time you read a row of text, create a new empty vector.
Call strtol repeatedly on the row you read, using push_back to collect them into the vector. When the output pointer is the same as the input pointer (this indicates failure, probably because you reached the end of the line), push_back the whole vector and start the next row.
Something like this:
std::vector< std::vector<long> > all_data;
std::string text_row;
while(getline(fin, text_row)) {
all_data.push_back();
std::vector<long>& this_row = *all_data.rend();
const char* p1 = text_row.c_str();
const char* p2;
while (1) {
long num = strtol(p2 = p1, &p1, 0);
if (p1 == p2) break;
this_row.push_back(num);
}
/* to ignore blank lines, add this code
if (this_row.empty()) all_data.pop_back();
*/
}
The following code shows how to solve your problem. It also shows how you can use RAII when opening a file. This is good practice when acquiring resources. By acquiring the resource in the constructor and releasing it in the destructor a resource leak can be prevented if an exeption is thrown. This is considered good practice in the C++ world.
#include <fstream>
#include <vector>
struct FileHandle
{
std::ifstream file_;
FileHandle(std::string file_name)
{
file_.open(file_name);
}
~FileHandle()
{
file_.close();
}
};
bool next_char_is_end_of_line(std::ifstream &file)
{
bool found = false;
char c;
file.get(c);
if(c == '\n')
found = true;
file.unget();
return found;
}
int main()
{
FileHandle fh("c:\\your_file.txt");
std::vector<std::vector<int> > v;
std::vector<int> current_line;
int x;
while(fh.file_ >> x)
{
current_line.push_back(x);
if(next_char_is_end_of_line(fh.file_))
{
v.push_back(current_line);
current_line.clear();
}
}
//Then just access each std::vector<std::vector<int>>
//v[0].size(); ...
return 0;
}
This code gives you a "jagged" vector by putting all numbers on each row into a separate vector. This vector is then added to main vector. So each line in the "vector" can have different lengths. I think you get the idea...
Good luck!
Try stringstream.
There are actually two problems, here:
how to recognize the input and ...
how to represent it in memory.
You spoke about "2d Array": is this a requirement or just an hypothesis? is the 2x5 size a requirement or just a sample?
You spoke about a file layout. It that mandatory, or not? Must you admit (and check) eventually misleading like more numbers, or misalignment? What do you have to do in case the row have 6 numbers the first and 4 the second?
A very simple solution can be use a 2x5 array and fill it up with a guarded loop:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdexcept>
const int ROWS=2;
const int COLS=5;
int main(int argc, char** argv)
{
int m[ROWS][COLS];
try
{
std::ifstream s(argv[1]);
if(!s) throw std::runtime_error("cannot open file");
for(int r=0; r<ROWS; ++r)
for(int c=0; c<COLS; ++c)
if(!(s >>m[r][c])
throw std::runtime_error("insufficient or bad input");
}
catch(const std::exception& e)
{
std::cout << "Reading error: " << e.what() << std::endl;
return -1;
}
std::cout << "read matrix is \n";
for(int r=0; r<ROWS; ++r)
{
for(int c=0; c<COLS; ++c)
std::cout << std::setw(8) << m[r][c];
std::cout << '\n';
}
std::cout << std::endl;
return 0;
}
This will read 10 numbers separated by "blanks", no matter how distributed and aligned.
(it is assumend the the 2x5 is a consrain.)
On the other end, you may have to detect yourself how wide the matrix is: the file can have any number of lines, each whatever number of elements long.
In this case you need a "flexible structure", and you need to identify lines and elements in the lines.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <utility>
int main(int argc, char** argv)
{
std::vector<std::vector<int> > m;
try
{
std::ifstream fs(argv[1]);
if(!fs) throw std::runtime_error("cannot open input file");
while(fs)
{
std::string line;
std::getline(fs,line);
std::vector<int> row;
std::stringstream ss(line);
int x;
while(ss >> x)
row.push_back(x);
if(!row.empty())
m.emplace_back(std::move(row));
}
}
catch(const std::exception& e)
{
std::cout << "Reading error: " << e.what() << std::endl;
return -1;
}
std::cout << "read lines: \n";
for(auto i=m.begin(); i!=m.end(); ++i)
{
for(auto j=i->begin(); j!=i->end(); ++j)
std::cout << std::setw(8) << *j;
std::cout << '\n';
}
std::cout << std::endl;
return 0;
}