使用 std: : fill 填充具有递增数字的向量

我想用 std::fill填充一个 vector<int>,但是不是一个值,矢量后面应该包含数字的递增顺序。

我尝试通过将函数的第三个参数迭代1来实现这一点,但是这只能给出填充了1或2的向量(取决于 ++操作符的位置)。

例如:

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
140677 次浏览

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).

this also works

j=0;
for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){
*it = j++;
}

Preferably use std::iota like this:

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:

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.

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.

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.)

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. :)

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;
}

Speaking of boost:

auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));

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, ...

We can use generate function which exists in algorithm header file.

Code Snippet :

#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;
}

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

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

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.

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.

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:

  1. Lambda captures outer scope [&] which means that i will be available inside expression
  2. item passed as a reference, therefore, it is mutable inside the vector

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; });

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;
}
}

Working demo C++11

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.