Reputation: 1569
I would like to fill a vector<int>
using std::fill
, but instead of one value, the vector should contain numbers in increasing order after.
I tried achieving this by iterating the third parameter of the function by one, but this would only give me either vectors filled with 1 or 2 (depending of the position of the ++
operator).
Example:
vector<int> ivec;
int i = 0;
std::fill(ivec.begin(), ivec.end(), i++); // elements are set to 1
std::fill(ivec.begin(), ivec.end(), ++i); // elements are set to 2
Upvotes: 132
Views: 178262
Reputation: 12731
C++23:
auto vec = std::views::iota(1, 100) | std::ranges::to<std::vector>();
Upvotes: 1
Reputation: 89214
Since C++ 23, ranges::iota
can be used.
#include <vector>
#include <numeric>
int main() {
std::vector<int> v(5); // initialize with 5 zeros
std::ranges::iota(v, 0); // fill with consecutive integers starting from 0
// v={0,1,2,3,4}
}
Alternatively, to add elements starting from an empty vector
, ranges::generate_n
can be used (since C++ 20) in conjunction with back_inserter
.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream> // only used for output in this example
int main() {
std::vector<int> v;
v.reserve(5); // allocate enough space for elements
std::ranges::generate_n(std::back_inserter(v), 5, [i=0]() mutable {return i++;});
// use ++i to start from 1 instead of 0
std::ranges::copy(v, std::ostream_iterator<int>(std::cout, " ")); // 0 1 2 3 4
}
Upvotes: 3
Reputation: 19767
Preferably use std::iota
like this:
#include <vector>
#include <numeric>
// ...
std::vector<int> v(100) ; // vector with 100 ints.
std::iota (std::begin(v), std::end(v), 0); // Fill with 0, 1, ..., 99.
That said, if you don't have any c++11
support (still a real problem where I work), use std::generate
like this:
#include <vector>
#include <algorithm>
// ...
struct IncGenerator {
int current_;
IncGenerator (int start) : current_(start) {}
int operator() () { return current_++; }
};
// ...
std::vector<int> v(100) ; // vector with 100 ints.
IncGenerator g (0);
std::generate( v.begin(), v.end(), g); // Fill with the result of calling g() repeatedly.
Upvotes: 190
Reputation: 1
You can create a function template make_vec
that will return a std::vector
with the elements in increasing order as shown below:
template<std::size_t N> std::vector<int> make_vec()
{
std::vector<int> tempArray(N);
int count = 0;
for (auto& elem : tempArray)
{
elem = ++count;
}
return tempArray;
}
int main()
{
std::vector<int> vec = make_vec<10>(); //uses ELEMENT_COUNT by default
for(const auto&elem: vec)
{
std::cout << elem << std::endl;
}
}
The output of the above program is:
1
2
3
4
5
6
7
8
9
10
Note that with c++20
you can even mark make_vec
as constexpr
. Demo C++20.
Upvotes: -1
Reputation: 492
I've seen the answers with std::generate but you can also "improve" that by using static variables inside the lambda, instead of declaring a counter outside of the function or creating a generator class :
std::vector<int> vec(10);
std::generate(vec.begin(), vec.end(), [] {
static int i = 0;
return i++;
});
I find it a little more concise
Upvotes: 12
Reputation: 33
The best way I've found would be to use std::generate_n
with std::back_insert_iterator
. This example is actually given in the cppreference page for std::back_insert_iterator. One change I would make to this example, however, would be to reserve the number of inserts you are about to make to minimize reallocations like so:
std::vector<int> v;
v.reserve(10);
std::generate_n(std::back_insert_iterator<std::vector<int>>(v), 10, [n=0]() mutable { return ++n; });
Upvotes: 1
Reputation: 1944
There is another option - without using iota. For_each + lambda expression can be used:
vector<int> ivec(10); // the vector of size 10
int i = 0; // incrementor
for_each(ivec.begin(), ivec.end(), [&](int& item) { ++i; item += i;});
Two important things why it's working:
Upvotes: 4
Reputation:
You should use std::iota
algorithm (defined in <numeric>
):
std::vector<int> ivec(100);
std::iota(ivec.begin(), ivec.end(), 0); // ivec will become: [0..99]
Because std::fill
just assigns the given fixed value to the elements in the given range [n1,n2)
. And std::iota
fills the given range [n1, n2)
with sequentially increasing values, starting with the initial value and then using ++value
.You can also use std::generate
as an alternative.
Don't forget that std::iota
is C++11 STL algorithm. But a lot of modern compilers support it e.g. GCC, Clang and VS2012 : http://msdn.microsoft.com/en-us/library/vstudio/jj651033.aspx
P.S. This function is named after the integer function ⍳
from the programming language APL, and signifies a Greek letter iota. I speculate that originally in APL this odd name was chosen because it resembles an “integer”
(even though in mathematics iota is widely used to denote the imaginary part of a complex number).
Upvotes: 65
Reputation: 41
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.
Upvotes: 0
Reputation: 1756
In terms of performance you should initialize the vector with use of reserve()
combined with push_back()
functions like in the example below:
const int numberOfElements = 10;
std::vector<int> data;
data.reserve(numberOfElements);
for(int i = 0; i < numberOfElements; i++)
data.push_back(i);
All the std::fill
, std::generate
, etc. are operating on range of existing vector content, and, therefore the vector must be filled with some data earlier. Even doing the following: std::vector<int> data(10);
creates a vector with all elements set to its default value (i.e. 0 in case of int
).
The above code avoids to initialize vector content before filling it with the data you really want. Performance of this solution is well visible on large data sets.
Upvotes: 2
Reputation: 6363
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
Upvotes: 0
Reputation: 3725
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;
}
Upvotes: 7
Reputation: 11577
this also works
j=0;
for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){
*it = j++;
}
Upvotes: 2
Reputation: 643
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, ...
Upvotes: 1
Reputation: 21749
Speaking of boost:
auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));
Upvotes: 2
Reputation: 19
If you really want to use std::fill
and are confined to C++98 you can use something like the following,
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
struct increasing {
increasing(int start) : x(start) {}
operator int () const { return x++; }
mutable int x;
};
int main(int argc, char* argv[])
{
using namespace std;
vector<int> v(10);
fill(v.begin(), v.end(), increasing(0));
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
Upvotes: 1
Reputation: 69
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. :)
Upvotes: 6
Reputation: 153909
My first choice (even in C++11) would be
boost::counting_iterator
:
std::vector<int> ivec( boost::counting_iterator<int>( 0 ),
boost::counting_iterator<int>( n ) );
or if the vector was already constructed:
std::copy( boost::counting_iterator<int>( 0 ),
boost::counting_iterator<int>( ivec.size() ),
ivec.begin() );
If you can't use Boost: either std::generate
(as suggested in
other answers), or implement counting_iterator
yourself, if
you need it in various places. (With Boost, you can use
a transform_iterator
of a counting_iterator
to create all
sorts of interesting sequences. Without Boost, you can do a lot
of this by hand, either in the form of a generator object type
for std::generate
, or as something you can plug into a hand
written counting iterator.)
Upvotes: 15
Reputation: 94299
If you'd rather not use C++11 features, you can use std::generate
:
#include <algorithm>
#include <iostream>
#include <vector>
struct Generator {
Generator() : m_value( 0 ) { }
int operator()() { return m_value++; }
int m_value;
};
int main()
{
std::vector<int> ivec( 10 );
std::generate( ivec.begin(), ivec.end(), Generator() );
std::vector<int>::const_iterator it, end = ivec.end();
for ( it = ivec.begin(); it != end; ++it ) {
std::cout << *it << std::endl;
}
}
This program prints 0 to 9.
Upvotes: 5