2
\$\begingroup\$

I have a matrix M of size [n_rows, n_cols] and a list of x and y pixel coordinates. I use these coordinates to draw a binary image. Here is my code:

std::vector<std::vector<double>> x;
std::vector<std::vector<double>> y;

// fill x and y

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

std::vector<std::vector<double>>::const_iterator iter_row_x = x.begin();
std::vector<std::vector<double>>::const_iterator iter_row_y = y.begin();

for (; iter_row_x != x.end(); ++iter_row_x, ++iter_row_y) {
    std::vector<double>::const_iterator iter_col_x = iter_row_x[0].begin();
    std::vector<double>::const_iterator iter_col_y = iter_row_y[0].begin();
    for (; iter_col_x != iter_row_x[0].end(); ++iter_col_x, ++iter_col_y) {
        unsigned int i = unsigned int(*iter_col_x);
        unsigned int j = unsigned int(*iter_col_y);
        M[i][j] = 1;
    }
}

I would like to know if there is a more elegant way to achieve this? My code above looks a bit bulky and error-prone for such a simple task.

\$\endgroup\$
  • 1
    \$\begingroup\$ Do you need 2D-matrices for x and y? Would something like std::vector<Point> xy suffice? (where Point is a struct with members double x and double y.) \$\endgroup\$ – Mikael H Jun 15 at 10:39
  • \$\begingroup\$ @MikaelH I need 2D-matrices since I have several objects. \$\endgroup\$ – recipe_for_disaster Jun 15 at 10:44
  • \$\begingroup\$ Okay, but I assume std::vector<std::vector<Point>> xy would be fine? \$\endgroup\$ – Mikael H Jun 15 at 10:55
  • \$\begingroup\$ @MikaelH For only one object, yes. But I have many objects. \$\endgroup\$ – recipe_for_disaster Jun 15 at 10:59
8
\$\begingroup\$

auto

Automatic type deduction is especially welcoming for iterators, as their types are bulky. We can rewrite to

std::vector<std::vector<double>> x;
std::vector<std::vector<double>> y;

// fill x and y

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

auto iter_row_x = x.cbegin(); //note cbegin to get const_iterator
auto iter_row_y = y.cbegin();

for (; iter_row_x != x.end(); ++iter_row_x, ++iter_row_y) {
    auto iter_col_x = iter_row_x->cbegin(); // iter_row_x[0].cbegin() = iter_row_x->cbegin()
    auto iter_col_y = iter_row_y->cbegin();
    for (; iter_col_x != iter_row_x[0].end(); ++iter_col_x, ++iter_col_y) {
        auto i = static_cast<unsigned int>(*iter_col_x); // be explicit about which cast you are using. Now you do not need to specify the type twice.
        auto j = static_cast<unsigned int>(*iter_col_y);
        M[i][j] = 1;
    }
}

But it's still wordy. Having separate vectors for x and y seems unnecessary, since it is expected that they should be of same length. Better create a structure for xy and create only one vector.

struct Point 
{
    double x;
    double y;
}

Then we have

std::vector<std::vector<Point>> xy;

// fill xy

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

for (auto iter_row_xy = xy.cbegin() ; iter_row_xy != xy.end(); ++iter_row_xy) {
    for (auto iter_col_xy = iter_row_xy->cbegin(); iter_col_x != iter_row_x[0].end(); ++iter_col_x, ++iter_col_y) {
        auto i = static_cast<unsigned int>(*iter_col_xy.x);
        auto j = static_cast<unsigned int>(*iter_col_xy.y);
        M[i][j] = 1;
    }
}

But we can do even better by using for range:

std::vector<std::vector<Point>> xy;

// fill xy

std::vector<std::vector<unsigned int>> M(n_rows, std::vector<unsigned int>(n_cols));

for (const auto& elements : xy){
    for (const auto& point : elements){
        auto i = static_cast<unsigned int>(point.x);
        auto j = static_cast<unsigned int>(point.y);
        M[i][j] = 1;
    }
}
| improve this answer | |
\$\endgroup\$
  • 4
    \$\begingroup\$ And with C++17 you can use structured bindings to simplify the inner for-loop: for (auto [x, y]: elements) {unsigned int i = x, j = y; M[i][j] = 1;} \$\endgroup\$ – G. Sliepen Jun 15 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.