I'm trying to find the fastest way for getting numbers from file. There can be negative numbers. My e.x. input:
5 3
-5 -6 2 -1 4
1 2 3 4
4 3 2 1
I'm using:
getline(cin, line);
istringstream linestream(line);
linestream >> var;
The result is okay but my program has run time error with last test, maybe min. 100 000 numbers. My question is, is there a faster way to get string and split it to numbers than my solution? The time is the most important.
If there's only numbers in your input, you could do:
std::vector<int> numbers;
int i;
while(cin >> i) {
numbers.push_back(i);
}
To stop the input from cin you'll need to send the EOF (End Of File) signal, which is either Ctrl+D or Ctrl+Z depending on your OS.
The input from a file will automatically stop when the end of the file is reached.
See c++ stringstream is too slow, how to speed up?
For your runtime error, you didn't post compilable code, and your error is in what you didn't post.
The best is make a function that reads a file line by line and puts each line elements in an array( if you are just printing just print it dont store in an array).I am using c function instead of c++ streams because for large data they are faster.The function should use fgetc which is faster than fscanf when used for large data.If in your system fgetc_unlocked works fine then you should replace that to fgetc
-5 -6 2 -1 4
1 2 3 4
Assume the input is like above and is stored in input.txt. Just make the input.txt in your dir and run the following code in the same dir. You can make changes later how you want to use the numbers
#include<iostream>
#include<cstdio>
using namespace std;
#define GC fgetc // replace with fgetc_unlocked if it works in your system(Linux)
//This function takes a line of f and put all integers into A
//and len is number of elements filled
void getNumsFromLine( FILE* f, int *A, int& len){
register char ch=GC(f);
register int n=0;
register bool neg = false;
len=0;
while( ch!='\n' ){
while( ch !='-' && (ch>'9' || ch<'0') ) ch=GC(f);
if( ch=='-') {
neg = true;
ch = GC(f);
}
while( ch>='0' && ch<='9' ){
n = (n<<3)+(n<<1)+ch-'0';
ch = GC(f);
}
if(neg) {
n=-n;
neg=false;
}
A[len++]=n;
n=0;
}
}
int main(){
FILE* f=fopen("input.txt", "r");
int A[10][2],len;
for( int i=0; i<2; i++ ){
getNumsFromLine( f, A[i], len );
for( int j=0; j<len; j++ ) cout << A[i][j] <<" ";
cout << endl;
}
fclose(f);
return 0;
}
Related
I am pretty new to coding so I am sure this is a stupid question. For a class I need to code an algorithm that determines the least amount of change to make some amount of money in C++.
This code needs to read numbers from a txt file so that the first line is the coin types (aka 1 cent, 2 cents, 4 cents, etc.). The second line is the total number that I want sorted into change. Then third line is a new set of coin types and the fourth line is a new total. The general pattern continues.
The txt file looks like -
1 2 5
10
1 3 7 12
29
1 2 4 8
15
1 7 11
14
I easily created the change algorithm myself, I am having problems getting the first line to be read into an array and then the next line to be read into a variable.
My code for the coinChange algorithm.
int coinChange(int coins[], int total, int size)
{
//Set high minimum
int min = 999999999;
//For all of the coins, see if it equals the value of total
for (int i = 0; i < size; i++) {
if (coins[i] == total) {
//If so return 1
return 1;
}
}
//Loop through
for (int j = 1; j <= total / 2; j++) {
if ((coinChange(coins, j, size) + coinChange(coins, total - j, size)) < min) {
min = coinChange(coins, j, size) + coinChange(coins, total - j, size);
}
}
return min;
}
I have tried using fgets and fscanf with no success so any advice would be very helpful.
If you use c++ as tadman commented already you can use something like that:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main()
{
std::stringstream ss("1 2 5\n10\n1 3 7 12\n29\n");
std::string line;
while(std::getline(ss, line))
{
std::stringstream lines(line);
std::vector<int> values;
std::string string_value;
while(std::getline(lines, string_value, ' '))
values.push_back(std::stoi(string_value));
std::getline(ss, line);
int value = std::stoi(line);
std::cout << "got: ";
for(const auto& v : values) std::cout << v << ", ";
std::cout << value << std::endl;
}
return 0;
}
Try it here http://cpp.sh/33bmy .
This reads a complete line and splits the coin types apart using a std::istringstream. The total amount on the next line is extracted the usual way.
I changed your function signature to take a std::vector and an int. Most of your code should remain the same if you replace your use of size with coins.size().
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int coinChange(const std::vector<int> &coins, int total)
{
// Set high minimum
int min = 999999999;
//
// Your code here. Don't need a size parameter, use coins.size() instead
//
return min;
}
int main()
{
std::vector<int> coins;
int total;
std::string line;
while (std::getline(std::cin >> std::ws, line) && std::cin >> total) {
std::istringstream iss(line);
for (int coin; iss >> coin; ) {
coins.push_back(coin);
}
coinChange(coins, total);
coins.clear(); // reset vector before the next inputs
}
}
Note: the use of std::ws inside the std::getline call is there to consume any leftover whitespace or newline from a previous input.
Ive searched and re-read but I can't figure this one out. I am simply trying to input a text file into a [i][j] string array. Which it does fine, but i need it to stop inputting into the array once it gets to the end of the line and start putting the second line in the 2nd array stop at the end of the line and so on..
My file contains 4 separate lines that read.
This is line one.
This is line two.
This is line three.
This is line four.
And my code reads it and mostly does what i need it to. But it puts everything into the array until it runs out of room then continues to the next row. It doesn't stop once it reaches the end of line one. Here is my code.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string arrayTextIn[25][25];
ifstream textIn;
textIn.open("sampleText.txt");
for(int i=0; i<25; i++)
for(int j=0; j<25; j++)
{
textIn >> arrayTextIn[i][j];
if(arrayTextIn[i][j] == "\n") //This is where I dont know how to proceed.
break;
}
for(int i=0; i<25; i++)
for(int j=0; j<25; j++)
cout << i << " " << j << " "<< arrayTextIn[i][j] << endl;
return 0;
}
This is the output but what i want is each line to start at a new [ith] row. Thanks for the help.
0 0 This
0 1 is
0 2 line
0 3 one.
0 4 This
0 5 is
0 6 line
0 7 two.
0 8 This
0 9 is
0 10 line
0 11 three.
0 12 This
0 13 is
0 14 line
0 15 four.
0 16
1 0
1 1
1 2
1 3
1 4
This is a two-step process.
The first step is to read the input, one line at a time, this would be reading each line of text in the input file:
ifstream textIn;
textIn.open("sampleText.txt");
for(int i=0; i<25; i++)
{
std::string line;
if (std::getline(textIn, line).eof())
break;
// Magic goes here.
}
So, what we've accomplished so far is read each line of input, up to the maximum of 25.
The second step is take each line of input, and divide it into whitespace-delimited words. This part goes where magic goes, above:
std::istringstream iline(line);
for(int j=0; j<25; j++)
{
std::string word;
if ((iline >> word).eof())
break;
arrayTextIn[i][j]=word;
}
You start by constructing an istringstream, which works exactly like ifstream, except that the input stream comes from a string.
Then, it's pretty much what you had originally, except now the scope is small enough to be easily handled with a single loop.
In conclusion: the way to approach a task of any moderate complexity is to divide it into two or more smaller task. Here, you take this relatively complicated task and turn it into two smaller, easier to implement tasks: first, reading each line of text, and, second, given a line of read text, divide each line into its individual words.
If you really want to maintain your design (2D-array) then this may be a fast solution:
for (int i = 0; i < 25; i++) {
std::string line;
std::getline(textIn, line); // read the entire line
if (textIn.eof()) {
// if reach the end of file, then break the cycle.
break;
}
if (line.size() > 0) { // avoid empty lines
int j = 0;
size_t finder;
// Cycle and looking for whitespace delimiters.
while (finder = line.find(' '), finder != std::string::npos && j < 25) {
// get a single word
auto token = line.substr(0, finder);
if (token != " ") {
// if that word is not a simple white-space then save it in the array. You can also std::move if C++11
arrayTextIn[i][j] = token;
++j;
}
// erase that part from the main line
line.erase(0, finder + 1);
}
}
}
I am having issues with the following code and I cant figure out why out of loop is not being printed. With this code I want the program to ignore any spaces inputted by the user and after a space is inputted the number previously entered is stored in an array location. Like this I want 6 and 78 to be stored in 2 array locations not store them individually as 6 7 8.
This is my code:
while ((in=getchar()) != '0')
{
if (in == ' ')
{
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
input[i]=in;
}
i++;
}
printf("Out of Loop");
My output when inputting 5 6 78 is:
assigning
space
assigning
space
assigning
assigning
assigning
With this output I doubt whether 78 is being stored in one memory location.
I would really appreciate your help,Thankyou
C++:
std::vector<int> v;
std::string s;
int i;
std::getline( std::cin, s); // read full line with whitespaces
std::istringstream iss( s); // prepare to process the line
while( iss >> i) v.push_back( i); // read into i and push into vector if
// operator>> was successful
C:
int array[ 10];
int i = 0, retval;
while( i < 10 && ( retval = scanf( "%d", &array[ i++])) == 1) ;
if( i == 10) {
// array full
}
if( retval == 0) {
// read value not an integer. matching failure
}
if( retval == EOF) {
// end of file reached or a read error occurred
}
You are deciding character by character. Thus, you will only store single digits or ignore those digits.
You could store the whole numbers like this (extending your code):
bool currentNumberStarted = false;
int currentNumber = 0;
int idx = 0;
while ((in=getchar()) != '0')// you probably want '\0' instead of '0'
{
if (in == ' ')
{
if (currentNumberStarted)
{
input[idx]=currentNumber;
idx++;
currentNumberStarted = false;
}
printf("space\n ");
continue;
}
else
{
printf("assigning\n ");
currentNumberStarted = true;
currentNumber *= 10;
currentNumber += in;
}
}
printf("Out of Loop");
First of all I highly doubt that your while loop will ever end, even if you made that to '\0' ,Because you are using char variable to store input. Not strings, Only strings uses '\0' at the end,How can we enter '\0' from keyboard..???. even if you want to keep it as '0',you would alwasy have to enter 0 as last number to end the loop(which i think you dont want to.)
So the Solution is this:-
After Entering Numbers You will Hit ENTER key, which would generate a newline character '\n' so you have to check for new line character('\n'), And as you are using getchar() function, it will returns EOF (-1) at the end of input, so its important to check for it too.So you have to check for both '\n' and EOF at once in while loop.And at last you should also check for array index number(it should be less than 1) in which you are storing numbers.
I made some effort to make you understand the program in comments.
int main()
{
int i=0;
int input[10]={0}; //here only 10 integers can be entered(hence i should be i<10)
int in; //To store input character
int num=0; //To store number which is converted from character.
int new=1; //To check if new number is started 0=false 1=True.
int count=0;//This is just to know how many numbers entered,also used to print numbers at end.
while ((in=getchar()) != '\n' && (in!=EOF) && i<10)//should check for both '\n' and EOF and array index also
{
if (in == ' ')
{
printf("space\n ");
if(new==0) //if new Number is not started yet.
{
new=1; //Start of a New number.(a number entered after space)
i++; //As new number is started it should be stored in new array index.
}
continue; //if space is entered just go to begining
}
else
{
printf("assigning\n ");
num=in-48; //converts a character to number (ex:- converts '3' to 3)
input[i]=(input[i]*10)+num; //storing the number..This is important do a paper work to understand this step.
new=0; //still in same number(we are still processing same number)
}
}
printf("Out of Loop \n");
count=i+1; //This gives correct count of numbers entered
for(i=0;i<count;i++) //to print numbers.
printf("%d ",input[i]);
return 0;
}
OUTPUT:-
E:>example.exe
78 2 65 998 1
assigning
assigning
space
assigning
space
.
.
.
space
assigning
Out of Loop
78 2 65 998 1
So I have to write a program to
=> analyze three different data files, and try to confirm Benford’s law. You will create a console application that opens each file, counts the number of values that start with ‘1’, ‘2’, ‘3’, etc., and then outputs the percentages of each digit.
I think I have it down but I keep getting an error in Dev C++.
int analyzeData(string fname) {
ifstream infile(string fname);
int tmp,count = 0;
float percents[9];
int nums[9] = { 0 };
if(!infile.good())
return 1;
while(!infile.eof())
{
infile >> tmp;
tmp = first(tmp);
if(tmp > 0)
{
nums[tmp - 1] ++;
count++;
}
}
It's saying that 'good', 'eof', and 'infile' are non-class type?
I don't know what that means!
Help would be much appreciated! thanks!
Firstly
ifstream infile(string fname);
should be
ifstream infile(fname);
Your version was a function prototype not a declaration of a variable.
Secondly this is the wrong way to loop to the end of a file
while (!infile.eof())
{
infile >> tmp;
...
}
this is the right way
while (infile >> tmp)
{
...
}
This must be the single most common error we see here. eof does not do what you think it does, and anyone who told you to write while (!infile.eof()) is just wrong.
Finally first(tmp) is not the correct way to get the first digit from an integer. You'll have to work a little harder than that.
Rather than read the input as integers, read the lines as strings, the grab the first digit from the string. Or you could read as an integer and then divide tmp by 10 until the result is < 10.
Make you life a little easier, and use the digit as an index into the array. You need to be able to index values 1 - 9, so you would need to declare your array a little bigger. ditto for percents.
int nums[9] = { 0 }; // works, but do less work
float percents[9];
int nums[10] = { 0 }; // do this, then you can us the digit to index nums[]
float percents[10];
You don't need the guard for tmp > 0, because you have room for all 10 digis,
//if( tmp > 0 )
//{
...
//}
You don't need to subtract one from tmp,
int analyzeData(string fname)
{
ifstream infile(fname);
int tmp,count = 0;
float percents[10];
int nums[10] = { 0 };
if(!infile.good())
return 1;
while(infile >> tmp)
{
tmp = first(tmp);
{
nums[tmp] ++;
count++;
}
}
if(count<1) count=1; //avoid division by zero
for( tmp=1; tmp<10; ++tmp )
cout<<tmp<<":"<<nums[tmp]<<",pct:"<<(nums[tmp]*1.0)/count<<eol;
}
I am trying to see what is the easiest way to read input from a text file with information:
7
12
v1-v2 7
v1-v3 11
v1-v4 1
v2-v4 12
v2-v5 5
v3-v4 8
v3-v6 10
v4-v5 6
v4-v6 3
v4-v7 4
v5-v7 9
v6-v7 2
Normally this should be very simple but I need to account for those first 2 lines which contain 2 different numbers needed.
So far I have set up:
int nodes;
int lines;
string line;
int count=0;
while(cin) {
getline(cin, line);
for(int i = 0; i < line.length(); i++) {
if(count >2)
break;
if(! (s[i] >= '0' && s[i] <= '9')
break;
else if(count=0) {
nodes = s[i]-'0';
}
else
lines = s[i]-'0';
count++;
}
//Space for code to account for other lines
}
So this is a round about way of getting those first 2 numbers but I believe there should be an easier way of doing this. Any suggestions or if someone can point me in the right direction
Why would you not read in the two numbers before the loop:
cin >> nodes >> lines;
In case there is nothing on the input the variables will be set to 0.
If you need to handle this in a better way, you can do something similar to this:
if (cin) cin >> nodes;
else { /* handle error situation */ }
if (cin) cin >> lines;
else { /* handle error situation */ }