I'd to populate/initialize a vector with linearly increased value. For example, for every element in this vector, I'd like the next one is a
more than the previous. Or the kth
element has a value of k*a
something like this:
float a = 1.132;
vector<float> v(100);
for (int n = 0; n < 100; ++n)
{
v[n] = n*a;
}
Is there a more elegant way to do it? Thanks.
A matlab example would be the linspace(beginning value, end value, number of points)
linspace(1,5, 6)
ans =
1.0000 1.8000 2.6000 3.4000 4.2000 5.0000
The first thing you could go is switch to using std::generate
or std::generate_n
instead of a for loop. The generate
version could look like
int main()
{
float a = 1.132;
std::vector<float> v(100);
std::generate(v.begin(), v.end(), [n = 0, &a]() mutable { return n++ * a; });
}
Another option is to create an iterator that will generate the value as you iterate it. This has the advantage that you do not need to initialize v
with any default constructed valued (this can be/is expensive). Then you use the vectors range constructor and it will initialize all of the elements. As long as the iterator abides by the forward iterator requirements then the vector will figure out the space needed (which if it is not random access causes a full iteration), allocate, and then initialize(full iteration). This could be expensive with the double iteration so it might not be any faster and could be slower then the generate case (since zero initializing is pretty fast).
If you have access to C++11 you can use std::generate
with a lambda :
std::generate(v.begin(), v.end(), [n = 0, &a] () mutable { return a * n++; });
However, for this use case a vector is hardly needed as said in the comments.
You can define a type that has an operator++
and a conversion to float
, and use std::iota
#include <algorithm>
#include <vector>
struct spacer
{
spacer(float scale, int count = 0) : scale(scale), count(count) {}
spacer operator++(){ ++count; return *this; }
operator float(){ return count * scale; }
private:
float scale;
int count;
};
int main()
{
std::vector<float> v(100);
std::iota(v.begin(), v.end(), spacer(1.132));
}
If you have access to boost
, you can instantiate your vector using that and boost::counting_iterator
#include <algorithm>
#include <vector>
#include <tuple>
#include <boost/iterator/counting_iterator.hpp>
struct spacer
{
spacer(float scale, int count = 0) : scale(scale), count(count) {}
spacer operator++(){ ++count; return *this; }
operator float() const{ return count * scale; }
bool operator==(const spacer & rhs) const{ return std::tie(count, scale) == std::tie(rhs.count, rhs.scale); }
private:
float scale;
int count;
};
int main()
{
using iter = boost::counting_iterator<spacer, std::forward_iterator_tag, std::ptrdiff_t>;
std::vector<float> v(iter(spacer(1.132)), iter(spacer(1.132, 100)));
}
If you are looking for something like the matlab linspace, it's not directly available in C++ but it's easy to write a function doing that. Like:
std::vector<float> linspace(float start, float end, size_t points)
{
std::vector<float> res(points);
float step = (end - start) / (points - 1);
size_t i = 0;
for (auto& e : res)
{
e = start + step * i++;
}
return res;
}
Then you can use it like:
int main()
{
std::vector<float> v = linspace(1, 5, 6);
for (auto f : v) std::cout << f << " ";
std::cout << std::endl;
return 0;
}
Output:
1 1.8 2.6 3.4 4.2 5