迭代 arma::mat 并检索元素位置

Iterating over arma::mat and retrieving element locations

我正在尝试按元素设置 arma::mat 的值,每个元素的值取决于每个元素的多索引(行、列)。 有没有办法在迭代期间检索元素的当前位置?

基本上,我希望能够做一些事情 ,其中 it.col()it.row() 允许检索当前元素的位置。 为了说明,arma::sp_mat iterator documentation) 中给出的示例是:

sp_mat X = sprandu<sp_mat>(1000, 2000, 0.1);

sp_mat::const_iterator it     = X.begin();
sp_mat::const_iterator it_end = X.end();

for (; it != it_end; ++it) {
  cout << "val: " << (*it)    << endl;
  cout << "row: " << it.row() << endl;  // only available for arma::sp_mat, not arma::mat
  cout << "col: " << it.col() << endl;  // only available for arma::sp_mat, not arma::mat
}

当然有很多变通方法可以获取 arma::mat 迭代的元素位置,最直接的可能是:

但是, 这些对我来说似乎相当老套且容易出错,因为它们需要使用矩阵大小,甚至需要手动处理索引。 我正在寻找一个更清洁的(也许是内部优化的)解决方案。我觉得 应该 是实现此目标的一种方式.. .

除了用于 arma::sp_mat 的解决方案外,其他对我来说“不错”的解决方案是使用 .imbue or .for_each,但其函子不仅接受元素的当前值,还接受其位置作为附加参数;目前这似乎不可能。

您似乎已经自己回答了您的问题。我希望犰狳为我们提供一个 .imbue 方法重载,它接收一个仿函数,其参数与犰狳对象的维度一样多,但目前它只接受一个没有参数的仿函数。然后可能最简单的选择(在我看来)是使用 lambda 捕获必要的信息,例如下面的代码

    arma::umat m(3, 3);
    {
        int i = 0;
        m.imbue([&i, num_rows = m.n_rows, num_cols = m.n_cols]() {
            arma::uvec sub = arma::ind2sub(arma::SizeMat{num_rows, num_cols}, i++);
            return 10 * (sub[0] + 1) + sub[1];
        });
    }

在这个例子中,每个元素被计算为其行索引加上列索引的 10 倍。我在这里捕获 ì 作为线性索引,并将它和 lambda 放在大括号内以界定其范围。

我也希望我能写出类似 auto [row_idx, col_idx] = arma::ind2sub( ... ) 的东西,但不幸的是 ind2sub returns 不适用于结构化绑定。

如果愿意,您还可以通过 const 引用捕获 m 并使用 arma::size(m) 作为 arma::ind2sub 的第一个参数。

查看犰狳源代码,row_col_iterator 提供了每个元素的行和列索引。这类似于稀疏矩阵迭代器,但不会跳过零。调整您的代码:

mat X(10,10,fill::randu);

mat::const_row_col_iterator it     = X.begin_row_col();
mat::const_row_col_iterator it_end = X.end_row_col();

for (; it != it_end; ++it) {
  cout << "val: " << (*it)    << endl;
  cout << "row: " << it.row() << endl;
  cout << "col: " << it.col() << endl;
}