vendredi 17 novembre 2023

How to iterate over ranges of a std::vector

I have a question on what's the best way to iterate over slices/ranges of a vector with C++11 or C++14. Let's say we have a std::vector that holds a bunch of values:

std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10};

This vector is used as input to calculate a value from n contiguous values, in operations similar to a moving average. For this purpose, I have a function foo that takes n contiguous elements as input, does some math, and outputs a value. This means this function looks something like the following declaration:

int foo(const std::vector<int> &v_range);

I want to apply foo to all elements of v to map them to another vector. I could pull that off by iterating over the vector, extract a subvector, and pass it to foo. See code below.

// Example program
#include <vector>
#include <iostream>

int foo(const std::vector<int> &v) {
    
    std::cout << "[";
    for(int e: v) {
        std::cout << e << ",";
    }
    std::cout << "]" << std::endl;
    return 0;
}

int main()
{
  std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10};
  std::vector<int> v_out;
  std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10};
  std::vector<int> v_out;
  const int n = 3;

  for (auto begin = v.begin(), end = std::next(v.begin(), n);
       std::next(begin, n - 1) != v.end();
       ++begin, ++end) {
      std::vector<int> v_slice(begin, end);
      v_out.push_back(foo(v_slice));
  }
}

Demo

The above works, but not only does it require a lot of boilerplate code but it also needlessly copy elements around.

I was wondering if C++ provided any clever way to easily iterate over slices/ranges of elements of a vector, which could be passed to either std::transform or std::for_each.

Alternatively, I was wondering if C++ offered any way to transform the input vector as a vector of vector ranges, similar to the following pseudocode:

  std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10};


  std::vector<std::vector<int>> v_sliced = { 
    {0,1,2},
    {1,2,3},
    {2,3,4}
    ///...
    {8,9,10}
  };

Any input is welcomed.

Aucun commentaire:

Enregistrer un commentaire