104

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

我尝试通过将函数的第三个参数迭代一个来实现这一点,但这只会给我填充 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
4

16 回答 16

144

std::iota最好像这样使用:

std::vector<int> v(100) ; // vector with 100 ints.
std::iota (std::begin(v), std::end(v), 0); // Fill with 0, 1, ..., 99.

也就是说,如果您没有任何c++11支持(在我工作的地方仍然是一个真正的问题),请std::generate像这样使用:

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.
于 2013-07-17T08:25:38.490 回答
54
于 2013-07-17T08:20:32.990 回答
15

我的第一选择(即使在 C++11 中)是 boost::counting_iterator

std::vector<int> ivec( boost::counting_iterator<int>( 0 ),
                       boost::counting_iterator<int>( n ) );

或者如果已经构建了向量:

std::copy( boost::counting_iterator<int>( 0 ),
           boost::counting_iterator<int>( ivec.size() ),
           ivec.begin() );

如果您不能使用 Boost:或者std::generate(如其他答案中所建议),或者counting_iterator自己实施,如果您在各个地方需要它。(使用 Boost,您可以使用 atransform_iteratorcounting_iterator创建各种有趣的序列。如果没有 Boost,您可以手动完成很多工作,可以是生成器对象类型的形式,std::generate也可以插入到手写计数迭代器。)

于 2013-07-17T08:41:55.967 回答
10

我已经看到了 std::generate 的答案,但您也可以通过在 lambda 中使用静态变量来“改进”这一点,而不是在函数之外声明一个计数器或创建一个生成器类:

std::vector<int> vec;
std::generate(vec.begin(), vec.end(), [] {
    static int i = 0;
    return i++;
});

我觉得它更简洁一些

于 2018-01-04T15:33:57.237 回答
7

我们可以使用算法头文件中存在的生成函数。

代码片段:

#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;
}
于 2017-07-06T18:46:52.567 回答
5

如果您不想使用 C++11 功能,可以使用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;
    }
}

这个程序打印 0 到 9。

于 2013-07-17T08:29:21.607 回答
4

std::iota 仅限于序列 n, n+1, n+2, ...

但是,如果您想用通用序列 f(0)、f(1)、f(2) 等填充数组怎么办?通常,我们可以避免使用状态跟踪生成器。例如,

int a[7];
auto f = [](int x) { return x*x; };
transform(a, a+7, a, [a, f](int &x) {return f(&x - a);});

将产生正方形序列

0 1 4 9 16 25 36

但是,此技巧不适用于其他容器。

如果你被 C++98 卡住了,你可以做一些可怕的事情,比如:

int f(int &x) { int y = (int) (long) &x / sizeof(int); return y*y; }

接着

int a[7];
transform((int *) 0, ((int *) 0) + 7, a, f);

但我不会推荐它。:)

于 2014-05-10T00:37:15.707 回答
4

还有另一种选择 - 不使用 iota。可以使用 For_each + lambda 表达式:

vector<int> ivec(10); // the vector of size 10
int i = 0;            // incrementor
for_each(ivec.begin(), ivec.end(), [&](int& item) { ++i; item += i;});

为什么它起作用的两个重要的事情:

  1. Lambda 捕获外部范围 [&] 这意味着 i 将在表达式内部可用
  2. 作为参考传递的项目,因此,它在向量内是可变的
于 2020-06-07T06:48:25.887 回答
2

这也有效

j=0;
for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){
    *it = j++;
}
于 2013-07-17T08:23:26.983 回答
2

说到提升:

auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));
于 2015-06-30T16:51:10.667 回答
2

在性能方面,您应该使用reserve()结合push_back()以下示例中的函数来初始化向量:

const int numberOfElements = 10;

std::vector<int> data;
data.reserve(numberOfElements);

for(int i = 0; i < numberOfElements; i++)
    data.push_back(i);

所有std::fill,std::generate等都在现有向量内容的范围内运行,因此向量必须提前填充一些数据。即使执行以下操作:std::vector<int> data(10);创建一个所有元素都设置为其默认值的向量(即 0 的情况下int)。

上面的代码避免在用你真正想要的数据填充之前初始化向量内容。该解决方案的性能在大型数据集上非常明显。

于 2019-07-15T09:25:55.050 回答
1

如果您真的想使用std::fill并且仅限于 C++98,您可以使用以下内容,

#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;
}
于 2015-02-28T16:45:37.877 回答
1

我知道这是个老问题,但我目前正在使用来处理这个问题。它需要 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, ...
于 2016-10-24T13:04:05.933 回答
0

我创建了一个简单的模板函数Sequence(),用于生成数字序列。该功能遵循seq()R(链接)中的功能。这个函数的好处是它可以生成各种数字序列和类型。

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

示例用法:

int main()
{
    auto vec = Sequence(0., 10., 0.5);
    for(auto &v : vec) {
        std::cout << v << std::endl;
    }
}

唯一需要注意的是,所有数字都应该是相同的推断类型。换句话说,对于双精度或浮点数,包括所有输入的小数,如图所示。

更新日期:2018 年 6 月 14 日

于 2018-03-07T21:27:42.957 回答
0

Brainsandwich 和 underscore_d 给出了非常好的想法。既然填充就是改变内容,那么 STL 算法中最简单的 for_each() 也应该可以填充:

std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i++;});    

广义捕获[i=o]赋予 lambda 表达式一个不变量并将其初始化为已知状态(在本例中为 0)。该关键字mutable允许每次调用 lambda 时更新此状态。

只需稍作修改即可获得一系列正方形:

std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i*i; i++;});

生成类似 R 的 seq 并不困难,但请注意,在 R 中,数字模式实际上是双精度数,因此实际上不需要参数化类型。只需使用双倍。

于 2019-11-16T05:11:42.007 回答
0

我发现最好的方法是使用std::generate_nwith std::back_insert_iterator。这个例子实际上是在std::back_insert_iterator 的 cppreference 页面中给出的。但是,我将对这个示例进行的一项更改是保留您将要进行的插入次数,以最大限度地减少重新分配,如下所示:

std::vector<int> v;
v.reserve(10);
std::generate_n(std::back_insert_iterator<std::vector<int>>(v), 10, [n=0]() mutable { return ++n; });
于 2022-02-11T23:19:06.913 回答