I'm attempting to create a program that takes a large number of stock prices. I have these prices stored in a .txt file with one double per row. There are an unknown number (probably thousands). I cannot get the data into an array which I can manipulate. I've been unable to solve this problem for a couple hours now. Whenever I attempt to read the data out of the file and then convert it to a double, I get weird thread errors and the program hangs. Can anyone show me how to read an unknown amount of doubles into an array.
string line;
vector<double> doubles;
fstream myfile ("/Users/jaychinnaswamy/Documents/PMHistory.txt",std::ios_base::in);
int x=0;
float a;
while (myfile >> a)
{
doubles[x]=a;
}
An example of the file structure is:
50.4000000000000
50.8000000000000
50.5000000000000
50.2100000000000
49.1500000000000
48.5000000000000
Thanks
You have created an empty vector here.
vector<double> doubles;
And here, you are indexing into the vector, as if it's not empty. It's still empty and you are accessing an invalid element.
doubles[x]=a;
Change that code to use std::vector::push_back().
doubles.push_back(a);
Two things obvious from the code I see (already mentioned in comments):
You don't increment x.
Even w/o increment, you access doubles[x] with x==0 when doubles has no elements. That's undefined behavior. You need to allocate elements ahead of time or use push_back to grow vector as needed.
The code you have submitted has a few issues. As stated by others, you have instantiated an empty std::vector and your code does assignments onto an index that does not exist. Since your problem revolves around an unknown amount of elements (dynamic size), use the push_back method of std::vector. I would advise you not convert from float to double through a. You know the data is a double and you want to store it as a double, so use double. Since this is just a piece of your code, you can utilize a for loop to make double a scope bound to the loading of the data.
Your code can be rewritten into:
std::ifstream myfile("/Users/jaychinnaswamy/Documents/PMHistory.txt");
std::vector<double> doubles;
for (double a; myfile >> a;) {
doubles.push_back(a);
}
However, if you don't require data verification, you know the file contains only doubles, and you really just want to import the numbers, then use the range constructor for std::vector to read the file for you via std::istream_iterator.
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::ifstream myfile("/Users/jaychinnaswamy/Documents/PMHistory.txt");
std::vector<double> doubles{(std::istream_iterator<double>(myfile)),
std::istream_iterator<double>()};
}
Pay special attention to the () around the first iterator argument of the std::vector range constructor. Without the () will result in syntactic ambiguity, also known as the "most vexing parse".
Related
In my C++ code,
vector <string> strVector = GetStringVector();
vector <int> intVector = GetIntVector();
So I combined these two vectors into a single one,
void combineVectors(vector<string>& strVector, vector <int>& intVector, vector < pair <string, int>>& pairVector)
{
for (int i = 0; i < strVector.size() || i < intVector.size(); ++i )
{
pairVector.push_back(pair<string, int> (strVector.at(i), intVector.at(i)));
}
}
Now this function is called like this,
vector <string> strVector = GetStringVector();
vector <int> intVector = GetIntVector();
vector < pair <string, int>> pairVector
combineVectors(strVector, intVector, pairVector);
//rest of the implementation
The combineVectors function uses a loop to add the elements of other 2 vectors to the vector pair. I doubt this is a efficient way as this function gets called hundrands of times passing different data. This might cause a performance issue because everytime it goes through the loop.
My goal is to copy both the vectors in "one go" to the vector pair. i.e., without using a loop. Am not sure whether that's even possible.
Is there a better way of achieving this without compromising the performance?
You have clarified that the arrays will always be of equal size. That's a prerequisite condition.
So, your situation is as follows. You have vector A over here, and vector B over there. You have no guarantees whether the actual memory that vector A uses and the actual memory that vector B uses are next to each other. They could be anywhere.
Now you're combining the two vectors into a third vector, C. Again, no guarantees where vector C's memory is.
So, you have really very little to work with, in terms of optimizations. You have no additional guarantees whatsoever. This is pretty much fundamental: you have two chunks of bytes, and those two chunks need to be copied somewhere else. That's it. That's what has to be done, that's what it all comes down to, and there is no other way to get it done, other than doing exactly that.
But there is one thing that can be done to make things a little bit faster. A vector will typically allocate memory for its values in incremental steps, reserving some extra space, initially, and as values get added to the vector, one by one, and eventually reach the vector's reserved size, the vector has to now grab a new larger block of memory, copy everything in the vector to the larger memory block, then delete the older block, and only then add the next value to the vector. Then the cycle begins again.
But you know, in advance, how many values you are about to add to the vector, so you simply instruct the vector to reserve() enough size in advance, so it doesn't have to repeatedly grow itself, as you add values to it. Before your existing for loop, simply:
pairVector.reserve(pairVector.size()+strVector.size());
Now, the for loop will proceed and insert new values into pairVector which is guaranteed to have enough space.
A couple of other things are possible. Since you have stated that both vectors will always have the same size, you only need to check the size of one of them:
for (int i = 0; i < strVector.size(); ++i )
Next step: at() performs bounds checking. This loop ensures that i will never be out of bounds, so at()'s bound checking is also some overhead you can get rid of safely:
pairVector.push_back(pair<string, int> (strVector[i], intVector[i]));
Next: with a modern C++ compiler, the compiler should be able to optimize away, automatically, several redundant temporaries, and temporary copies here. It's possible you may need to help the compiler, a little bit, and use emplace_back() instead of push_back() (assuming C++11, or later):
pairVector.emplace_back(strVector[i], intVector[i]);
Going back to the loop condition, strVector.size() gets evaluated on each iteration of the loop. It's very likely that a modern C++ compiler will optimize it away, but just in case you can also help your compiler check the vector's size() only once:
int i=strVector.size();
for (int i = 0; i < n; ++i )
This is really a stretch, but it might eke out a few extra quantums of execution time. And that pretty much all obvious optimizations here. Realistically, the most to be gained here is by using reserve(). The other optimizations might help things a little bit more, but it all boils down to moving a certain number of bytes from one area in memory to another area. There aren't really special ways of doing that, that's faster than other ways.
We can use std:generate() to achieve this:
#include <bits/stdc++.h>
using namespace std;
vector <string> strVector{ "hello", "world" };
vector <int> intVector{ 2, 3 };
pair<string, int> f()
{
static int i = -1;
++i;
return make_pair(strVector[i], intVector[i]);
}
int main() {
int min_Size = min(strVector.size(), intVector.size());
vector< pair<string,int> > pairVector(min_Size);
generate(pairVector.begin(), pairVector.end(), f);
for( int i = 0 ; i < 2 ; i++ )
cout << pairVector[i].first <<" " << pairVector[i].second << endl;
}
I'll try and summarize what you want with some possible answers depending on your situation. You say you want a new vector that is essentially a zipped version of two other vectors which contain two heterogeneous types. Where you can access the two types as some sort of pair?
If you want to make this more efficient, you need to think about what you are using the new vector for? I can see three scenarios with what you are doing.
The new vector is a copy of your data so you can do stuff with it without affecting the original vectors. (ei you still need the original two vectors)
The new vector is now the storage mechanism for your data. (ei you
no longer need the original two vectors)
You are simply coupling the vectors together to make use and representation easier. (ei where they are stored doesn't actually matter)
1) Not much you can do aside from copying the data into your new vector. Explained more in Sam Varshavchik's answer.
3) You do something like Shakil's answer or here or some type of customized iterator.
2) Here you make some optimisations here where you do zero coping of the data with the use of a wrapper class. Note: A wrapper class works if you don't need to use the actual std::vector < std::pair > class. You can make a class where you move the data into it and create access operators for it. If you can do this, it also allows you to decompose the wrapper back into the original two vectors without copying. Something like this might suffice.
class StringIntContainer {
public:
StringIntContaint(std::vector<std::string>& _string_vec, std::vector<int>& _int_vec)
: string_vec_(std::move(_string_vec)), int_vec_(std::move(_int_vec))
{
assert(string_vec_.size() == int_vec_.size());
}
std::pair<std::string, int> operator[] (std::size_t _i) const
{
return std::make_pair(string_vec_[_i], int_vec_[_i]);
}
/* You may want methods that return reference to data so you can edit it*/
std::pair<std::vector<std::string>, std::vector<int>> Decompose()
{
return std::make_pair(std::move(string_vec_), std::move(int_vec_[_i])));
}
private:
std::vector<std::string> _string_vec_;
std::vector<int> int_vec_;
};
This is the beginnings of a program that will read the numbers in an input file and put them into an array, and then sort them ascending and print them into an output file.
I am having trouble with the function that records how many numbers there are in the input file (I am trying to do this while putting the numbers in the array).
Here is the code of the function. There are no errors. Whenever I run the program it prints the amount of numbers in the input as 0.
int store (int arg[], int numsize, istream& infile)
{
while (infile >> arg[ //i dont know what to put here// ]) {
numsize++;
}
return numsize;
}
There are several problems with your code:
In order to put anything in the square brackets, you need to be sure that arg has enough space for it
However, you cannot be sure of that, because you have no idea how many items will be entered
Taking numsize as a parameter is useless, because you can't modify it anyway.
This code ignores C++ Standard Library containers in favor of C-style arrays.
Fortunately, all of this can be fixed with switching your container from C-style arrays to std::vector<int>:
std::vector<int> arg;
Now the entire read operation could then be finished in a single line of code:
std::copy(
std::istream_iterator<int>(infile),
std::istream_iterator<int>(),
std::back_inserter(arg)
);
You do not need to count elements in your code, because arg.size() provides you with access to the number of elements that have been read.
So far, I am trying to get my program to find the amount of bonds and element can have, provided by the user's input. I thought the easiest way of defining the same variable (bonds) across many different strings (name of the element) would be to create a struct and define the elements as members of that struct:
#include <iostream>
#include <string>
using namespace std;
struct element {
int bonds;
} Hydrogen, Helium, Lithium, Beryllium, Boron, Carbon, Nitrogen, Oxygen;
int Hydrogen.bonds=1;
int main()
{
string x;
int ans;
cout<<"Enter an element to find the amount of bonds it can have.";
cin>>x;
cout<<x" has "x.bonds" bonds.";
return 0;
};
Then, the program returns 1 with the errors:
expected initializer before ‘.’ token
int Hydrogen.bonds=1;
and
‘std::string’ has no member named ‘bonds’
I am writing this program as I learn about C++, but I can't find an easier solution to this. I'm trying to basically list the elements, then define their bond counts (e.g. Hydrogen.bonds=1; Carbon.bonds=4; Nitrogen.bonds=3;).
Is there a better way of doing this?
Your program won't compile because of two invalid lines
int Hydrogen.bonds=1;
This doesn't work because by starting with int the compiler expects a new variable; however, you provide an existing one, so it aborts. You should fix this by using a constructor or adding Hydrogen.bonds = 1 to main.
The second troublesome line
cout<<x" has "x.bonds" bonds.";
This one causes issues because you're missing <<. Unfortunately, x is a string and won't refer to the Element you want it too. Instead, it will just print their input back.
What you want to do is use a lookup table. I suggest looking into std::map. First you'd set its members. (something like: table[element_string] = element_properties) Then you can reference it easily with table[element_string] and it will return whatever you set it to.
reference material for std::map
cplusplus - http://www.cplusplus.com/reference/map/map/?kw=map
Yes, there is a better way.
You are essentially making a lookup table between an element and the number of bonds. I would start by doing that first (a std::map would be an easy start). You just need to populate it either as a static or at the top of the main() function.
The next problem is the output. Make sure you have enough operators (<<) in the right locations.
I am on a mobile and can't really write up a solution for you, but that's how I would approach your initial problem description.
I would like to create a vector (arma::uvec) of integers - I do not ex ante know the size of the vector. I could not find approptiate function in Armadillo documentation, but moreover I was not successfull with creating the vector by a loop. I think the issue is initializing the vector or in keeping track of its length.
arma::uvec foo(arma::vec x){
arma::uvec vect;
int nn=x.size();
vect(0)=1;
int ind=0;
for (int i=0; i<nn; i++){
if ((x(i)>0)){
ind=ind+1;
vect(ind)=i;
}
}
return vect;
}
The error message is: Error: Mat::operator(): index out of bounds.
I would not want to assign 1 to the first element of the vector, but could live with that if necessary.
PS: I would really like to know how to obtain the vector of unknown length by appending, so that I could use it even in more general cases.
Repeatedly appending elements to a vector is a really bad idea from a performance point of view, as it can cause repeated memory reallocations and copies.
There are two main solutions to that.
Set the size of the vector to the theoretical maximum length of your operation (nn in this case), and then use a loop to set some of the values in the vector. You will need to keep a separate counter for the number of set elements in the vector so far. After the loop, take a subvector of the vector, using the .head() function. The advantage here is that there will be only one copy.
An alternative solution is to use two loops, to reduce memory usage. In the first loop work out the final length of the vector. Then set the size of the vector to the final length. In the second loop set the elements in the vector. Obviously using two loops is less efficient than one loop, but it's likely that this is still going to be much faster than appending.
If you still want to be a lazy coder and inefficiently append elements, use the .insert_rows() function.
As a sidenote, your foo(arma::vec x) is already making an unnecessary copy the input vector. Arguments in C++ are by default passed by value, which basically means C++ will make a copy of x before running your function. To avoid this unnecessary copy, change your function to foo(const arma::vec& x), which means take a constant reference to x. The & is critical here.
In addition to mtall's answer, which i agree with,
for a case in which performance wasn't needed i used this:
void uvec_push(arma::uvec & v, unsigned int value) {
arma::uvec av(1);
av.at(0) = value;
v.insert_rows(v.n_rows, av.row(0));
}
TL;DR: Help me pass vector array input into a function that originally took in int pointers and ints.
I am in a college class that is learning about well-known algorithms. In this class, we use C++ to code the given algorithms. There was no pre-req class to learn C++, so my knowledge is pretty low when it comes to some of the major stuff with programming.
My problem: I have to create a program that takes an input file, sorts it with the user's choice of sorting algorithm, and write the results to an output file. My original code that works perfectly uses an input file of 20 items, placed into an array of length 20, and sorts no problem with each individual sorting algorithm.
Since last night, the only thing I have changed is that my input goes to a vector array, since the teacher will give us files of varying length (10 items to 1,000,000 items). I have four sorting algorithms that need to sort these given input files. Only one of them works, and it does not pass any variables into the function.
The other 3 originally passed in array pointers and other variables, however they do not work with my new input now going to a vector array instead of an int array. I know that what I am passing in needs to be changed, but I have no idea how to do this correctly. I have tried many different ways from sources found on the internet (with pointers and references), but I have had no luck. Here is some snipets of the code I'm using.
vector<int> A;
void insertionSort() // This works no problem as is.
void split(int* A, int* B, int low, int high) //code for Merge-Sort
{
//recurisvely calls split() and splitMerge()
}
void splitMerge(int* A, int* B, int low, int mid, int high) // more code for Merge-Sort
{
// more code for Merge-Sort
}
//quickSort() and countSort() also pass ints and do not work either.
//small part of main()
for (i = 0; unsorted >> temp; i++)
{
A.push_back(temp);
cout << A[i] << "\n";
length++; //I use int length extensively in for-loops in my functions
}
Last thing. I do not get an error when trying to run the Merge-Sort. It just freezes my console window.
conversion from vector to array is done this way
vector vInts;
...fill the vector
int * intArr=vInts[0]
so you don't need to modify your code too much
I believe there is not enough code to make an accurate prediction on where the error may be, but I think the problem is that the sorting algorithms is doing something like A++ with you pointers to access the next member.
Because arrays store the pointer to the next array inside the object and not on adjacent cells of memory, your algorithms are cycling through stuff they shouldn't.
If this is the case, the solution to your problem is to use an iterator instead of a pointer.
void split(A.begin(), B.begin(), int low, int high)