Используйте std:: fill для заполнения вектора с увеличением числа
Я хотел бы заполнить 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
Ответы
Ответ 1
Предпочтительно используйте 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.
Ответ 2
Вы должны использовать алгоритм 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
- это алгоритм STL 11 STL. Но многие современные компиляторы поддерживают его, например. GCC, Clang и VS2012: http://msdn.microsoft.com/en-us/library/vstudio/jj651033.aspx
Ответ 3
Мой первый выбор (даже в С++ 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 вы можете использовать
a transform_iterator
a counting_iterator
, чтобы создать все
рода интересных последовательностей. Без Boost вы можете много сделать
этого вручную, либо в виде типа объекта генератора
для std::generate
, или как что-то, что вы можете подключить к руке
написанный счетчиком итератора.)
Ответ 4
Если вы предпочитаете использовать функции С++ 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.
Ответ 5
Я видел ответы с помощью std :: generate, но вы также можете "улучшить" это, используя статические переменные внутри лямбды, вместо объявления счетчика вне функции или создания класса генератора:
std::vector<int> vec;
std::generate(vec.begin(), vec.end(), [] {
static int i = 0;
return i++;
});
Я нахожу это немного более кратким
Ответ 6
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
Однако этот трюк не будет работать с другими контейнерами.
Если вы застряли с С++ 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);
Но я бы не рекомендовал его.:)
Ответ 7
это также работает
j=0;
for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){
*it = j++;
}
Ответ 8
Мы можем использовать generate функцию, которая существует в файле заголовка алгоритма.
Фрагмент кода:
#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;
}
Ответ 9
Если вы действительно хотите использовать std::fill
и ограничены С++ 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
Говоря об усилении:
auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));
Ответ 11
Я знаю, что это старый вопрос, но сейчас я играю с library, чтобы справиться именно с этой проблемой. Для этого требуется С++ 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
Я создал простую шаблонную функцию 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;
}
}
Единственное предостережение в том, что все числа должны быть одного и того же предполагаемого типа. Другими словами, для двойных или плавающих чисел, включите десятичные дроби для всех входных данных, как показано.
Обновлено: 14 июня 2018 г.
Ответ 13
С точки зрения производительности вы должны инициализировать вектор с использованием 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
).
Приведенный выше код избегает инициализации векторного содержимого перед заполнением его данными, которые вам действительно нужны. Производительность этого решения хорошо видна на больших наборах данных.