I would like to fill a vector
using std::fill
, but instead of one value, the vector should contain numbers in increasing order after.
std::iota is limited to a sequence n, n+1, n+2, ...
But what if you want to fill an array with a generic sequence f(0), f(1), f(2), etc.? Often, we can avoid a state tracking generator. For example,
int a[7];
auto f = [](int x) { return x*x; };
transform(a, a+7, a, [a, f](int &x) {return f(&x - a);});
will produce the sequence of squares
0 1 4 9 16 25 36
However, this trick will not work with other containers.
If you're stuck with C++98, you can do horrible things like:
int f(int &x) { int y = (int) (long) &x / sizeof(int); return y*y; }
and then
int a[7];
transform((int *) 0, ((int *) 0) + 7, a, f);
But I would not recommend it. :)
I created a simple templated function, Sequence()
, for generating sequences of numbers. The functionality follows the seq()
function in R (link). The nice thing about this function is that it works for generating a variety of number sequences and types.
#include <iostream>
#include <vector>
template <typename T>
std::vector<T> Sequence(T min, T max, T by) {
size_t n_elements = ((max - min) / by) + 1;
std::vector<T> vec(n_elements);
min -= by;
for (size_t i = 0; i < vec.size(); ++i) {
min += by;
vec[i] = min;
}
return vec;
}
Example usage:
int main()
{
auto vec = Sequence(0., 10., 0.5);
for(auto &v : vec) {
std::cout << v << std::endl;
}
}
The only caveat is that all of the numbers should be of the same inferred type. In other words, for doubles or floats, include decimals for all of the inputs, as shown.
Updated: June 14, 2018
I know this is old question, but I am currently playing with library to handle exactly this problem. It requires c++14.
#include "htl.hpp"
htl::Token _;
std::vector<int> vec = _[0, _, 100];
// or
for (auto const e: _[0, _, 100]) { ... }
// supports also custom steps
// _[0, _%3, 100] == 0, 4, 7, 10, ...
brainsandwich and underscore_d gave very good ideas. Since to fill is to change content, for_each(), the simplest among the STL algorithms, should also fill the bill:
std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i++;});
The generalized capture [i=o]
imparts the lambda expression with an invariant and initializes it to a known state (in this case 0). the keyword mutable
allows this state to be updated each time lambda is called.
It takes only a slight modification to get a sequence of squares:
std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i*i; i++;});
To generate R-like seq is no more difficult, but note that in R, the numeric mode is actually double, so there really isn't a need to parametrize the type. Just use double.
We can use generate function which exists in algorithm header file.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
vector<int>v(10);
int n=0;
generate(v.begin(), v.end(), [&n] { return n++;});
for(auto item : v)
{
cout<<item<<" ";
}
cout<<endl;
return 0;
}
Speaking of boost:
auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));