问题描述
我正在尝试逐个设置arma::mat
元素的值,每个元素的值取决于每个元素的多索引(行,列)。
是否可以在迭代过程中检索元素的当前位置?
基本上,我希望能够执行like in the sparse matrix iterator,其中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
迭代的元素位置,最直接的方法可能是:
- 在行和列的大小上使用嵌套
for
循环。 - 使用单个
for
循环,并使用矩阵大小将迭代次数转换为行和列索引。 - 某种形式的“压缩”迭代,对象包含或计算相应的索引。
但是,这些对我来说似乎很hacky且容易出错,因为它们需要处理矩阵大小,甚至需要手动处理索引。 我正在寻找更清洁的(也许是内部优化的)解决方案。在我看来,应该应该是实现这一目标的一种方法...
除了用于arma::sp_mat
的解决方案之外,其他对我来说这样的“不错”的解决方案将使用.imbue
或.for_each
,但函子不仅接受元素的当前值,而且接受还将其位置作为附加参数;目前看来这不可能。
解决方法
您似乎已经回答了自己的问题。我希望armadillo为我们提供了.imbue
方法重载,该方法重载函数的函子数量与armadillo对象的维数相同,但目前它仅接受不带参数的函子。然后(我认为)可能是最简单的选择是使用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
返回的内容不适用于结构化绑定。
如果愿意,还可以通过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;
}