Подтвердить что ты не робот

Используйте 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
4b9b3361

Ответ 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).

Приведенный выше код избегает инициализации векторного содержимого перед заполнением его данными, которые вам действительно нужны. Производительность этого решения хорошо видна на больших наборах данных.