Я хотел бы заполнить 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
std::iota
вместоstd::fill
(в любом случае, если ваш компилятор достаточно новый, чтобы его поддерживать).std::vector
. Повышенная версия - это шаблон функции, а «имя типа» первого аргумента определяет концепцию. Трудно сказать, потому что я могу найти только очень формальную спецификацию, а не простое описание, но я думаю, что этоstd::vector
соответствует концепции.Ответы:
Желательно использовать
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.
источник
iota
означает? (Похоже, что кто-то неправильно набрал одинаково ясноitoa
.)Вы должны использовать
std::iota
алгоритм (определенный в<numeric>
):std::vector<int> ivec(100); std::iota(ivec.begin(), ivec.end(), 0); // ivec will become: [0..99]
Потому что
std::fill
просто присваивает заданное фиксированное значение элементам в заданном диапазоне[n1,n2)
. Иstd::iota
заполняет заданный диапазон[n1, n2)
последовательно увеличивающимися значениями, начиная с начального значения и затем используя.++value
Вы также можете использоватьstd::generate
в качестве альтернативы.Не забывайте, что
std::iota
это алгоритм STL C ++ 11. Но многие современные компиляторы поддерживают его, например GCC, Clang и VS2012: http://msdn.microsoft.com/en-us/library/vstudio/jj651033.aspxPS Эта функция названа в честь целочисленной функции
⍳
из языка программирования APL и обозначает греческую букву йота. Я предполагаю, что изначально в APL это нечетное имя было выбрано потому, что оно напоминает“integer”
(хотя в математике йота широко используется для обозначения мнимой части комплексного числа).источник
iota
был в STL более 15 лет назад, поэтому некоторые компиляторы всегда поддерживали его, задолго до C ++ 11Мой первый выбор (даже в 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_iterator
из acounting_iterator
для создания всевозможных интересных последовательностей. Без Boost вы можете многое сделать вручную, либо в виде типа объекта-генератораstd::generate
, либо как что-то, что вы можете подключить к рукописный счетный итератор.)источник
std::vector
вызывается? Должен быть конструктором диапазона , но может бытьboost::counting_iterator
неявно преобразован в InputIterator ?Я видел ответы с помощью std :: generate, но вы также можете «улучшить» это, используя статические переменные внутри лямбда, вместо объявления счетчика вне функции или создания класса генератора:
std::vector<int> vec; std::generate(vec.begin(), vec.end(), [] { static int i = 0; return i++; });
Я нахожу это немного более кратким
источник
static
здесь неправильная семантика, ИМО. Я бы использовал обобщенный захват,[i = 0]() mutable
чтобы было ясно, что переменная привязана к конкретному экземпляру лямбда, а не к его сгенерированному типу класса. Трудно придумать ситуацию, при которой на практике будет различие, и это, вероятно, укажет на сомнительный дизайн, но в любом случае я думаю, что семантика лучше при использовании переменной-члена. Кроме того, это делает код более лаконичным; теперь тело лямбды может быть единственным оператором.Если вы не хотите использовать функции 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.
источник
std::iota
, нет?it
иend
определены вне цикла for. По какой причине?std::vector<int>::const_iterator it = vec.begin(), end = ivec.end()
(ни повторяющийся набор, ни повторный звонок)? И строка длиннее, ну, это C ++, и вы все равно не обойдете случайный разрыв строки (а дни старых добрых 80-символьных дисплеев закончились). Но это дело вкуса, я думаю, и ты уже давно получил мой голос.Мы можем использовать генерировать функцию которая существует в файле заголовка алгоритма.
Фрагмент кода:
#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; }
источник
n
членом лямбды через обобщенный захват[n = 0]() mutable
, поэтому он не загрязняет окружающую область.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);});
создаст последовательность квадратов
Однако этот трюк не работает с другими контейнерами.
Если вы застряли на 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);
Но я бы не рекомендовал это. :)
источник
Кстати о наддуве:
auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));
источник
это тоже работает
j=0; for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){ *it = j++; }
источник
С точки зрения производительности вы должны инициализировать вектор с использованием функций в
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
).Приведенный выше код позволяет избежать инициализации векторного содержимого перед его заполнением данными, которые вам действительно нужны. Производительность этого решения хорошо видна на больших наборах данных.
источник
Есть еще вариант - без йоты. Можно использовать выражение For_each + лямбда:
vector<int> ivec(10); // the vector of size 10 int i = 0; // incrementor for_each(ivec.begin(), ivec.end(), [&](int& item) { ++i; item += i;});
Две важные вещи, почему это работает:
источник
Если вы действительно хотите использовать
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; }
источник
Я знаю, что это старый вопрос, но сейчас я играю с библиотекой для решения именно этой проблемы. Требуется 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, ...
источник
_
, зарезервированы для реализации там.Я создал простую шаблонную функцию
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; } }
Единственное предостережение: все числа должны быть одного предполагаемого типа. Другими словами, для чисел типа double или float включите десятичные дроби для всех входных данных, как показано.
Информация обновлена: 14 июня 2018 г.
источник
brainsandwich и underscore_d дали очень хорошие идеи. Поскольку заполнение означает изменение содержимого, for_each (), самый простой из алгоритмов STL, также должен заполнить счет:
std::vector<int> v(10); std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i++;});
Обобщенный захват
[i=o]
придает лямбда-выражению инвариант и инициализирует его известным состоянием (в данном случае 0). ключевое словоmutable
позволяет обновлять это состояние каждый раз, когда вызывается лямбда.Чтобы получить последовательность квадратов, требуется лишь небольшая модификация:
std::vector<int> v(10); std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i*i; i++;});
Сгенерировать R-подобный seq не сложнее, но обратите внимание, что в R числовой режим на самом деле двойной, поэтому действительно нет необходимости параметризовать тип. Просто используйте двойной.
источник