使用std :: fill来填充向量越来越多的数字

时间:2013-07-17 08:15:53

标签: c++ stl

我想使用vector<int>填充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

15 个答案:

答案 0 :(得分:89)

最好像这样使用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.

答案 1 :(得分:29)

您应该使用std::iota算法:

  std::vector<int> ivec;
  std::iota(ivec.begin(), ivec.end(), 0);

因为std::fill只是将给定的固定值分配给给定范围[n1,n2]中的元素。并且std::iota使用顺序递增的值填充给定范围[n1,n2],从初始值开始然后使用++value。您还可以使用std::generate作为替代。

不要忘记std::iota是C ++ 11 STL算法。但是很多现代编译器都支持它,例如GCC,Clang和VS2012:http://msdn.microsoft.com/en-us/library/vstudio/jj651033.aspx

答案 2 :(得分:9)

我的第一选择(即使在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,你可以使用 一个transform_iterator counting_iterator来创建所有 各种有趣的序列。没有Boost,你可以做很多事情 这可以用生成器对象类型的形式 对于std::generate,或者你可以插入一只手 写计数迭代器。)

答案 3 :(得分: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。

答案 4 :(得分: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);

但我不推荐它。 :)

答案 5 :(得分:4)

我已经看过std :: generate的答案,但你也可以&#34;改进&#34;通过在lambda中使用静态变量,而不是在函数外声明一个计数器或创建一个生成器类:

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

我发现它更简洁

答案 6 :(得分:2)

这也有效

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

答案 7 :(得分:2)

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

代码段:

public class FirebaseHelper {
    DatabaseReference db;
    Boolean saved=null;
    Boolean saved1=null;

    ArrayList<Paints> paints=new ArrayList<>();
    ArrayList<String> keys=new ArrayList<>();

    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }
     //READ THEN RETURN ARRAYLIST FOR SEARCH ITEMS IN CASE OF SEARCHING ABOUT ITEM
    public ArrayList<Paints> retrieveSearch(final String item) {
        db.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                fetchDataSearch(dataSnapshot,item);
            }
            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                fetchDataSearch(dataSnapshot,item);
            }
            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
            }
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
        return paints;
    }

    //IMPLEMENT FETCH DATA AND FILL ARRAYLIST FOR SEARCH
    private void fetchDataSearch( DataSnapshot dataSnapshot,String item)
    {
        paints.clear();

        //sorting and searching
        final DatabaseReference myRef = db.child("items");
        Query query = myRef.orderByChild("type").startAt(item)
                .endAt(item + "\uf8ff");

        query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
                    Paints paint=messageSnapshot.getValue(Paints.class);

                    paints.add(paint);
                    //Toast.makeText(FindDataActivity.this, "found " + type + " unit: " + unit + " price " + price, Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

    }

答案 8 :(得分:2)

还有另一种选择-不使用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捕获外部作用域[&],这意味着我可以在表达式内部使用
  2. 作为参考传递的项目,因此,它在矢量内部是可变的

答案 9 :(得分: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;
}

答案 10 :(得分:0)

说到提升:

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

答案 11 :(得分:0)

我知道这是一个老问题,但我现在正在玩library来处理这个问题。它需要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, ...

答案 12 :(得分:0)

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

#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日

答案 13 :(得分:0)

就性能而言,您应使用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::fillstd::generate等都在现有矢量内容的范围内运行,因此,矢量必须更早地填充一些数据。即使执行以下操作:std::vector<int> data(10);也会创建一个向量,并将所有元素设置为其默认值(例如,int时为0)。

上面的代码避免了在用您真正想要的数据填充矢量内容之前初始化矢量内容。在大型数据集上,该解决方案的性能显而易见。

答案 14 :(得分: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中,数字模式实际上是双精度的,因此实际上不需要参数化该类型。只需使用double。