Создайте вектор с шагом c ++ - PullRequest
2 голосов
/ 07 ноября 2019

Можно ли создать вектор из значения в другое с фиксированным шагом, не используя цикл в c ++?

Например, я хочу построить вектор от 1 до 10 с шагом 0,5. В MATLAB я могу сделать это следующим образом:

vector = [1:0.5:10];

Есть ли что-то подобное в c ++?

Ответы [ 6 ]

4 голосов
/ 07 ноября 2019

С помощью std::generate_n вы можете

std::vector<double> v;
const int size = 10 * 2 - 1;
v.reserve(size);
std::generate_n(std::back_inserter(v), size, []() { static double d = 0.5; return d += 0.5; });

LIVE

3 голосов
/ 07 ноября 2019

Вам нужен где-то цикл. Матлаб просто скрывает петлю от тебя. Если вы часто этим занимаетесь, просто создайте функцию, чтобы упростить ее использование:

#include <vector>

auto make_vector(double beg, double step, double end) 
{
    std::vector<double> vec;
    vec.reserve((end - beg) / step + 1);
    while (beg <= end) {
        vec.push_back(beg);
        beg += step;
    }
    return vec;
}

int main() {
    auto vec = make_vector(1, 0.5, 10);
}
2 голосов
/ 07 ноября 2019

Это невозможно без цикла, но вы можете скрыть цикл, используя, например, std::generate или std::generate_n:

constexpr size_t SIZE = (10 - 1) * 2;
std::vector<double> data(SIZE);

double new_value = 1.0;
std::generate(begin(data), end(data) [&new_value]()
{
    double current_value = new_value;
    new_value += 0.5;
    return current_value;
});

Конечно, это довольно много для написания, и явный цикл, вероятно, будет лучше:

std::vector<double> data;
for (double i = 1.0; i <= 10; i += 0.5)
    data.push_back(i);

Если шаг равен единице (например, 1 или1.0) тогда вы можете использовать std::iota вместо:

std::vector<double> data(10);
std::iota(begin(data), end(data), 1.0);  // Initializes the vector with values from 1.0 to 10.0
0 голосов
/ 07 ноября 2019

Простое решение с использованием библиотеки Ranges-v3 :

#include <range/v3/all.hpp>

auto make_vector(double min, double step, double max) {
    const auto size = static_cast<std::size_t>((max - min) / step);
    return ranges::views::iota(std::size_t{0}, size + 1) | 
           ranges::views::transform([min, step](auto i) { return min + step * i; }) |
           ranges::to<std::vector>();
}

int main() {   
    auto vec = make_vector(1, .5, 5);
    for (auto x : vec)
        std::cout << x << ' ';

    // Output: 1 1.5 2 2.5 3 3.5 4 4.5 5
}

Диапазоны будут часть C ++ 20.

0 голосов
/ 07 ноября 2019

Если вам нужно многое из этого, вы можете легко написать свою собственную функцию, которая может работать с любым контейнером (который поддерживает резерв и может быть заполнен std::generate):

template <typename TContainer>
TContainer fill(typename TContainer::value_type start, 
                typename TContainer::value_type step, 
                typename TContainer::value_type end) {
    size_t size = static_cast<size_t>((end - start)/step + 1);
    TContainer output(size);
    std::generate(std::begin(output), std::end(output), 
        [&start, step]() { 
            return std::exchange(start, start + step);
        }
    );
    return output;
}

Тогда вы можете использовать его следующим образом:

auto vec = fill<std::vector<int>>(0, 2, 10);
auto list = fill<std::list<float>>(1, 0.3, 5);

Живой пример

И вы получите:

vec: 0, 2, 4, 6, 8, 10
list: 1, 1.3, 1.6, 1.9, 2.2, 2.5, 2.8, 3.1, 3.4, 3.7, 4, 4.3, 4.6, 4.9
0 голосов
/ 07 ноября 2019

Нет, в С ++ таких вещей нет. Вам нужно будет создать цикл и заполнить ваш вектор, так что-то вроде:

std::vector<double> v;
v.reserve(19);
for(size_t i = 2; i < 21; ++i)
{
    v.push_back(i / 2.);
}

Я использую здесь целочисленный цикл вместо двойного цикла с приращениями .5, чтобы убедиться в количестве элементовЯ получаю и минимизирую ошибки округления чисел (.5 хорошо, но не 1/3, например).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...