C ++ добавляет константу к срезу вектора - PullRequest
0 голосов
/ 01 мая 2019

Я знаю, с помощью transform я могу добавить константу к некоторому вектору, например, так:

std::vector<int> a(3, 2);
std::transform( a.begin(), a.end(), a.begin(), std::bind2nd( std::plus<double>(), 1 ) );

Мне было интересно, как я могу изменить transform, чтобы добавить константу к некоторому срезу [index:end] извектор, например, последние два элемента.

Я могу сделать это с помощью цикла, например:

for (int i=1; i < a.size(); i++) {
    a.at(i) += 1;
}

, но, возможно, есть лучший вариант

Ответы [ 4 ]

2 голосов
/ 01 мая 2019

Причина, по которой алгоритмы используют итераторы, а не контейнеры, именно для таких случаев.

Общий способ адаптации среза в стиле Python состоит в добавлении +ve значений к begin и -ve к end.Предполагая, что есть по крайней мере два элемента, приращение последних двух элементов будет

auto start = a.end() - 2;
auto finish = a.end();
std::transform( start, finish , start, std::bind2nd( std::plus<double>(), 1 ) );
2 голосов
/ 01 мая 2019

Только последние N элементы? Используйте обратный итератор:

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

int main() {
  std::vector<int> a(3, 2);
  std::transform(a.rbegin(), std::next(a.rbegin(), 2), a.rbegin(),
                 [](auto n) { return n + 1; });

  for (auto n : a) {
    std::cout << n << '\n';
  }
  return 0;
}

(Использование std::next() вместо просто a.rbegin() + 2 облегчает задачу, если вам по какой-то причине необходимо изменить a на тип контейнера, в котором нет случайных итераторов.)

1 голос
/ 01 мая 2019

Вы можете использовать диапазон (std::span в C ++ 20, gsl::span ранее) для представления своего среза. Если вы не знаете о пролетах, взгляните на:

Что такое «промежуток» и когда я должен его использовать?

Так что, если вы напишите,

// ... vector a gets defined
auto slice = std::span(a).subspan(some_index);

Срез теперь ведет себя так же, как и любой стандартный контейнер библиотеки. В частности, вы могли бы написать:

std::transform(slice.begin(), slice.end(), slice.begin(), [](auto v) { return v + 1; });
1 голос
/ 01 мая 2019

Тот же код после небольшого рефакторинга:

std::vector< int > a(3, 2);

auto start = a.begin();
auto end   = a.end();
auto func  = [](auto val) {
    return val + 1;
};

std::transform(start, end, start, func);

Теперь, изменив значения start и end, можно изменить только срез.

Для этого std::advance может использоваться:

std::advance(start, 1);
std::advance(end, -1);

В приведенном выше коде:

  • start это 1 элемент после начала (2-й элемент - элемент синдекс 1).
  • end - это 1 элемент с конца.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...