How to put data line by line into a vector - c++

I want to read a text file line by line (I do not have many integers in each line). I want to sort each line and put them into a vector of a vector. The problem is I cannot insert them into vector line by line. I cannot let them stop at the end of the line. This is what I have now. Can anyone help me?
For example, my text file like this:
1 5 3 7 29 17
2 6 9 3 10
3 89 54 67 34
I want my output like this:
1: 1 3 5 7 17 29
2: 2 3 6 9 10
3: 3 34 54 67 89
vector<int> v;
vector<vector<int>> G_AL;
if(line!=0){ // Build matrics
string lines;
while (getline(fin, lines)) {
istringstream os(lines);
float temp;
while(os >> temp ) {
if(temp != '\n') {
v.push_back(temp);
sort(v.begin(), v.end());
// get v
}
else
{
}
G_AL.push_back(v);
}
}
}

Try this:
std::stringstream fin("2 1 3\n4 6 5\n10 9 7 8"); // Test data
std::vector<std::vector<int>> G_AL;
std::string lines;
while (getline(fin, lines)) {
std::istringstream os(lines);
std::vector<int> v;
float temp;
while(os >> temp)
v.push_back(temp);
sort(v.begin(), v.end());
G_AL.push_back(v);
}
for (size_t i=0; i<G_AL.size(); ++i)
{
std::cout << i+1 << ": ";
for (auto const & v : G_AL[i])
std::cout << v << " ";
std::cout << std::endl;
}
There are some problems in the code you provided:
The v vector is declared outside of the loop, so the values keeps accumulating every line since v is not cleared. Declaring it inside the loop fixes the problem and avoid having to clear it.
The sort can be done only once we finished reading the line.
You push the v vector into G_AL after ever value instead of after every line.
You compare a float with a character (\n), which doesn't work. In fact, the line os >> temp will evaluate to false if there is no floating point value to read, so there is no need to test once more for the end of the stream.

Related

Delete first column of 2d vector matrix read in using sstream

I have a 2d vector where the rows are unequal. I have been trying to delete the first column but have no luck look at previous stackoverflow posts.
example data:
1 2 4 5 6 6
1 2 3 4 6 6 8
Code to read in data:
myfile.open("test.txt");
if(myfile.is_open())
{
while(getline(myfile, line)){
//cout << "This line: ";
if(line != "")
{
istringstream is(line);
sortVec.push_back(std::vector<int>( std::istream_iterator<int>(is),
std::istream_iterator<int>() ) );
}
}
}
else
{
cout << "Myfile is not open" << endl;
}
myfile.close();
When I try to erase the first column using std:vector:
int columnIndex = 0;
for(auto& row:sortVec){
row.erase(next(row.begin(), columnIndex));
}
I get a segmentation fault.
I have tried the following stackoverflow posts as well.
How to delete column in 2d vector, c++
Additionally when I create a vector manually everything works perfect so I am lost at the moment.
Desired output:
2 4 5 6 6
2 3 4 6 6 8
The answer was that don't forget to check empty lines when using getline. The last line of my file was empty.

Read a file line by line with specific data C++

I have a file with this format:
11
1 0
2 8 0
3 8 0
4 5 10 0
5 8 0
6 1 3 0
7 5 0
8 11 0
9 6 0
10 5 7 0
11 0
The first line is the number of lines, so I can make a loop to read the file with the number of lines.
For the other lines, I would like to read the file line by line and store the data until I get a "0" on the line that's why there is a 0 at the end of each line.
The first column is the task name.
The others columns are the constraints name.
I tried to code something but It doesn't seem to work
printf("Constraints :\n");
for (int t = 1; t <= numberofTasks; t++)
{
F >> currentTask;
printf("%c\t", currentTask);
F >> currentConstraint;
while (currentConstraint != '0')
{
printf("%c", currentConstraint);
F >> currentConstraint;
};
printf("\n");
};
The "0" represents the end of the constraints for a task.
I think my code doesn't work properly because the constraint 10 for the task 4 contains a "0" too.
Thanks in advance for your help
Regards
The problem is that you are reading individual characters from the file, not reading whole integers, or even line-by-line. Change your currentTask and currentConstraint variables to int instead of char, and use std::getline() to read lines that you then read integers from.
Try this:
F >> numberofTasks;
F.ignore();
std::cout << "Constraints :" << std::endl;
for (int t = 1; t <= numberofTasks; ++t)
{
std::string line;
if (!std::getline(F, line)) break;
std::istringstream iss(line);
iss >> currentTask;
std::cout << currentTask << "\t";
while ((iss >> currentConstraint) && (currentConstraint != 0))
{
std::cout << currentConstraint << " ";
}
std::cout << std::endl;
}
Live Demo
That being said, the terminating 0 on each line is unnecessary. std::getline() will stop reading when it reaches the end of a line, and operator>> will stop reading when it reaches the end of the stream.
Live Demo

How to read sequences with spaces and stop when the user presses "enter" in C++?

As title, I am a beginner in learning C++.
I want to read several sequences(s1,s2,s3...) containing integers seperated by spaces into an array,and stop reading s1 to read s2 by pressing "enter".
#
Here's the test data:
4 9 6 6
1 2 3 4
3 3 5 6 9 15 18 15 18 30 3 3 5 6 9 15 18 15 18 30 1 9 9 25 36
The result I expect would be :
arr[0]={4,9,6,6}
arr[1]={1,2,3,4}
arr[2]={3,3,5,6,9,15,18,15,18,30,3,3,5,6,9,15,18,15,18,30,1,9,9,25,36}
#
I used a time consuming way to read data into my array:
while(1){
int i=0,j=0;
int arr[100][25];
char test;
while(1){
stringstream ss;
cin.get(test);
if(test==' '){
ss<<seq;
seq.clear();
ss>>arr[i][j];
j++;
continue;
}
else if(test=='\n'){
ss<<seq;
seq.clear();
ss>>arr[i][j];
i++;
j=0;
break;
}
else{
seq=seq+test;
}
}
}
Online Judge will show "TLE" when the program reads big integers.
I know that break down integers into characters is a time consuming work,
what can I do with my program?
One way to do this could be using strings. The example below, based on this answer, reads each line in a string, and splits it by space. It will work only if the numbers are split by single spaces. The split numbers are stored in a vector of strings in the example, and can be converted to int using stoi.
string nums;
while(getline(cin,nums)) {
istringstream iss(nums);
vector<string> tokens;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(tokens));
// print what is added
for(int i = 0; i < tokens.size(); i++) {
cout << tokens[i] << " ";
}
cout << endl;
}

Reading integer input from file into a dynamic array and printing it

I am attempting to write a program that reads in integers from an input file and outputs a dynamic array. This array would be the size of the input. For verification, I'd also like to print the array. The output will be passed to a function to create a sorted linked list.
I tried the following, but it did not work:
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int get, count = 0;
while (input >> get)
count++;
cout << "Number of integers: " << count << endl;
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
delete[] array;
Here's an online example of my code.
The problem is that the output shows some weird numbers, completely unrelated to the input:
Number of integers: 8
-1217944384
-1217944384
-1
538976266
540226080
824193844
Where did I go wrong?
As πάντα ῥεῖ pointed out, the solutions that I did provide are not totally safe, that's why I will provide a third example, using boost::spirit.
See the points fast fix and good solution, as well as πάντα ῥεῖ's answer to get it working without using boost.
my personal favourite solution: note that this example does require to have read the text file into a string.
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
template<typename Iterator>
bool
parse_numbers(Iterator first, Iterator last, std::vector<int>& v)
{
bool r =
boost::spirit::qi::parse(first, last,
// Begin grammar
(boost::spirit::qi::int_[boost::phoenix::push_back(
boost::phoenix::ref(v), _1)]
% *(boost::spirit::qi::char_("a-zA-Z")
| boost::spirit::ascii::space)));
if (first != last) // fail if we did not get a full match
return false;
return r;
}
const std::string s = "23 43 12 67 \n18 15 22\n12 xxx 23 12 xx 34556 11 11 www";
std::string::const_iterator start = s.begin(), stop = s.end();
std::vector<int> results;
parse_numbers(start, stop, results)));
for(int i : results)
std::cout << value << ' ';
the result would be, as expected:
23 43 12 67 18 15 22 12 23 12 34556 11 11
The above example is partially built on the example given in the boost::spirit documentation.
input >> get moves the current curser position, so after your while loop you have nothing left to read.
fast fix:
ifstream input;
input.open("file.txt");
int get, count = 0;
while (input >> get)
count++;
input.close();
input.open("file.txt");
int *array = new int [count];
for (int i = 0; i < count; i++)
{
input >> array[i];
}
for (int i = 0; i < count; i++)
{
cout << *(array+i) << endl;
}
input.close();
delete[] array;
To close and reopen the stream should work, but there are more efficient solutions out there...
good solution:
One could be to read and insert into a dynamically growing vector for example. See the documentation for further reference.
std::vector<int> dataArray;
while (input >> get)
{
dataArray.insert(dataArray.end(), get);
}
for(auto&& value : dataArray)
{
std::cout << value << std::endl;
}
That would have multiple advantages:
allocating the vector on the stack prevents you from being forced to call delete. An alternative would be a standard smart pointer.
the for each loop works even without counting the elements. If you need the number of elements you could just ask the vector about his size.
Your code has several misconceptions and flaws:
(1) After applying this loop to count your inputs
while (input >> get)
count++;
the input stream's state is left over the result of last extraction operation (input >> get) that has failed. Thus no further input can be read, without completely resetting the stream.
(2) The second loop you're showing
for (int i = 0; i < count; i++) {
input >> array[i];
}
uses the input stream in invalid state (the whole stream was already read to input.eof()), and thus reading from it results in 'weird values' (in other words: It's undefined behavior at this point).
I would write the following proven code to solve this
// Your literal input file formatting goes here
istringstream input(R"inp(
23 43 12 67
18 15 22
12 xxx 23 12 xx 34556 11 11 www
)inp");
int current;
vector<int> allIntInputs;
while (input >> current || !input.eof()) {
if(input.fail()) {
input.clear();
string crap;
input >> crap; // read anything up to the next
// whitespace delimiter (the default deleimiters)
continue; // with the next item
}
// Everything's fine we'll add another number
allIntInputs.push_back(current);
}
// Print all integer values extracted
cout << "Integer values read from input:" << endl;
for(vector<int>::iterator it = allIntInputs.begin();
it != allIntInputs.end();
++it) {
if(it != allIntInputs.begin()) {
cout << ' ';
}
cout << *it;
}
cout << endl;
Output
Integer values read from input:
23 43 12 67 18 15 22 12 23 12 34556 11 11

Read from string into stringstream

When I try to parse whitespace seperated double values from a string, I found this curious behaviour that the string is read out in a cyclic manner.
Here's the program:
stringstream ss;
string s("1 2 3 4");
double t;
list<double> lis;
for(int j=0; j!=10; ++j){
ss << s;
ss >> t;
lis.push_back(t);
}
for(auto e : lis){
cout << e << " ";
}
Here the output:
1 2 3 41 2 3 41 2 3 41
If I append a trailing space as s= "1 2 3 4 "; I get
1 2 3 4 1 2 3 4 1 2
Now the questions:
1) If I don't know how many entries are in the string s, how do I read all into the list l?
2) which operator<< am I actually calling in ss << s;? Is it specified to read circularly?
3) Can I do the parsing in a better way?
Thanks already!
Here's the fixed code (thanks to timrau):
// declarations as before
ss << s;
while(ss >> t){
lis.push_back(t);
}
// output as before
This produces:
1 2 3 4
as desired. (Don't forget to clear your stringstream by ss.clear() before treating the next input. ;))
Another useful comment from HeywoodFloyd: One could also use boost/tokenizer to "split" the string, see this post
You can test the return value of >>.
while (ss >> t) {
lis.push_back(t);
}
It's not specified to read circularly. It's ss << s appending "1 2 3 4" to the end of the stream.
Before the 1st loop:
""
After 1st ss << s:
"1 2 3 4"
After 1st ss >> t:
" 2 3 4"
After 2nd ss << s:
" 2 3 41 2 3 4"
Then it's clear why you get 1 2 3 41 2 3 41 2 3 41 if there is no trailing space in s.
then use s.length() for strings containing unknown number of entries, if you use your approach.
Or, as suggested by timrau, just initialize your stringstream once.
stringstream ss;
string s("1 2 3 4 5 6 7 8");
ss << s;
double t;
list<double> lis;
while (ss >> t) {
lis.push_back(t);
}
for(auto e : lis){
cout << e << " ";
}
This stackoverflow post includes a boost tokenizer example. You may want to tokenize your string and iterate through it that way. That will solve the no trailing space problem timrau pointed out.