2

I have std::vector<std::vector<double>> A(300, std::vector<double>(500)).

I want to create a new vector with sub-range of A: sub-vector[5:10][25:100]. How can I do this?

L. F.
  • 19,445
  • 8
  • 48
  • 82
Alexanov
  • 125
  • 18

4 Answers4

1

You can use iterators. First create the vector:

std::vector<std::vector<double>> sub_vector;
sub_vector.reserve(5);

Then populate it with the range constructor of vector:

for (std::size_t i = 5; i < 10; ++i) {
    sub_vector.emplace_back(A[i].begin() + 25, A[i].begin() + 100);
}

Notes:

  • You are responsible for ensuring that the indexes are in range. Otherwise this results in undefined behavior.

  • This deals with close-open ranges. If you want close-close ranges, you need to add one to the end indexes.

L. F.
  • 19,445
  • 8
  • 48
  • 82
  • Not sure that sub range notation of OP is close-open and not close-close though. Easy to adapt anyway. – Jarod42 Nov 02 '19 at 09:47
  • @Jarod42 Hmm ... I was assuming Python, in which slices are close-open. Good point. – L. F. Nov 02 '19 at 09:48
1

There are no simple notations like that, you have to roll your own:

std::vector<std::vector<double>> A(300, std::vector<double>(500));
std::vector<std::vector<double>> subranges;

subranges.reserve(11 - 5);
std::transform(A.begin() + 5, A.begin() + 11,
               std::back_inserter(subranges),
               [](const auto& inner){ // [](const std::vector<double>& inner) {
                   return std::vector<double>(inner.begin() + 25,
                                              inner.begin() + 101);
               });
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

Yet another solution

Using a function to do the job.

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

constexpr size_t MaxRows = 300;
constexpr size_t MaxColumns = 500;
using MyType = double;
using Columns = std::vector<MyType>;
using Matrix = std::vector<Columns>;

void copySubMatrix( const Matrix& source,Matrix& destination,const size_t& startRow,const size_t& endRow,const size_t& startColumn, const size_t& endColumn)
{
    // Clear destination matrix
    destination.clear();
    // Copy rows end columns
    std::for_each(source.begin() + startRow, source.begin() + endRow + 1, [&](const Columns & c) {
        Columns row{ c.begin() + startColumn, c.begin() + endColumn + 1};
        destination.push_back(row); });
}

int main() {

    // Define source matrix with given size and empty destination matrix
    Matrix A(MaxRows, Columns(MaxColumns));
    Matrix result{};

    // Fill source matrix with running values
    std::for_each(A.begin(), A.end(), [i = 0](Columns & c) mutable {for (MyType& m : c) m = i++; });


    // Copy the given range to the destination matrix
    copySubMatrix(A, result, 5, 10, 25, 100);

    // Display destination matrix
    std::for_each(result.begin(), result.end(), [](const Columns & c) {
        std::copy(c.begin(), c.end(), std::ostream_iterator<MyType>(std::cout, " ")); std::cout << "\n"; });

    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44
  • Instead of taking a reference argument, returning the vector makes the function more flexible to use. Also, the "fill source matrix" part can be done with `std::iota`. – L. F. Nov 02 '19 at 10:04
0

You can do this by iterating over one dimension:

std::vector<vector<double>> main_vector(300, std::vector<double>(500));
std::vector<vector<double>> sub_vector;
std::vector<double>::const_iterator first, last;

unsigned int x_pos_start=5, x_pos_end=10;
unsigned int y_pos_start=25, y_pos_end=100;

sub_vector.resize(x_pos_end - x_pos_start + 1);
for(size_t i=x_pos_start; i<=x_pos_end; ++i)
{
    first = main_vector[i].begin() + y_pos_start;
    last = main_vector[i].begin() + y_pos_end;
    sub_vector[i].insert(sub_vector[i].begin(), first, last);
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Iman Kianrostami
  • 482
  • 3
  • 13