tags:

views:

1141

answers:

5

Hi all,

I know how to fill an std::vector with non-trivial initial values, e.g. sequence numbers:

void IndexArray( unsigned int length, std::vector<unsigned int>& v )
{
    v.resize(length);
    for ( unsigned int i = 0; i < length; ++i )
    {
        v[i] = i;
    }
}

But this is a for-loop. Is there an elegant way to do this with less lines of code using stl functionality (and not using Boost)?

+9  A: 

You can use the generate algorithm, for a more general way of filling up containers:

#include <iostream>
#include <algorithm>
#include <vector>

struct c_unique {
   int current;
   c_unique() {current=0;}
   int operator()() {return ++current;}
} UniqueNumber;


int main () {
  vector<int> myvector (8);
  generate (myvector.begin(), myvector.end(), UniqueNumber);

  cout << "\nmyvector contains:";
  for (vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    cout << " " << *it;

  cout << endl;

  return 0;
}

This was shamelessly lifted and edited from cplusplusreference.

moogs
He may want to start with v[i] == i but change it later in the code.
paxdiablo
yes probably, i was hoping he'd explain the case. there may possibly be a better method than filling em up first. Like a lazy evaluation-ish way or something.
moogs
I made my question more general, since the question was really about initializing with non-trivial values. I indeed wanted to fill the array with index numbers, to be able to permute them later. There probably will be other solutions to that as well.
andreas buykx
right, removed the question. Perhaps you can post that permutation question? The solution might be interesting :)
moogs
@moog NOTE: generate may make a _copy_ or copies of the function you provide it, this code might generate the sequence "1 1 1 1 ..". Instead, use tr1::ref to pass a reference-wrapper that refers to UniqueNumber, to avoid copies: generate(.. tr1::ref(UniqueNumber) );
Aaron
+3  A: 

If you're using SGI STL (or a derivative, such as STLPort), you can use iota. :-)

void IndexArray(unsigned int length, vector<unsigned int>& v)
{
    vector<unsigned int>(length).swap(v);
    iota(v.begin(), v.end(), 0);
}
Chris Jester-Young
+3  A: 

I usually go with std::generate plus a simple generator:

template <typename T>
struct gen {
    T x;
    gen(T seed) : x(seed) { }

    T operator ()() { return x++; }
};

generate(a.begin(), a.end(), gen<int>(0));
Konrad Rudolph
+2  A: 

There is also a iota() function in adobe.ASL, (and a value_iterator as well). In boost, there is a counting_iterator, and I suspect a few other ways to do generate number sequences on the fly in boost.

Luc Hermitte
A: 

If you have a C style array you can use std:copy, e.g.,

int c_array[] = {3,4,5};

const int* pbegin = &c_array[0];
const size_t c_array_size = sizeof(c_array) / sizeof(c_array[0]);
const int* pend  = pbegin + c_array_size;

std::vector<int> v;
v.reserve(c_array_size);
std::copy(pbegin, pend, std:back_inserter(v));
maccullt