迭代 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
迭代的元素位置,最直接的可能是:
- 对行和列大小使用嵌套
for
循环。
- 使用单个
for
循环,并使用矩阵大小,将迭代次数转换为行和列索引。
- 某种形式的“压缩”迭代,对象包含或计算相应的索引。
但是, 这些对我来说似乎相当老套且容易出错,因为它们需要使用矩阵大小,甚至需要手动处理索引。
我正在寻找一个更清洁的(也许是内部优化的)解决方案。我觉得 应该 是实现此目标的一种方式.. .
除了用于 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;
}
我正在尝试按元素设置 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
迭代的元素位置,最直接的可能是:
- 对行和列大小使用嵌套
for
循环。 - 使用单个
for
循环,并使用矩阵大小,将迭代次数转换为行和列索引。 - 某种形式的“压缩”迭代,对象包含或计算相应的索引。
但是, 这些对我来说似乎相当老套且容易出错,因为它们需要使用矩阵大小,甚至需要手动处理索引。 我正在寻找一个更清洁的(也许是内部优化的)解决方案。我觉得 应该 是实现此目标的一种方式.. .
除了用于 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;
}