遍历 arma::mat 并检索元素位置

Posted

技术标签:

【中文标题】遍历 arma::mat 并检索元素位置【英文标题】:Iterating over arma::mat and retrieving element locations 【发布时间】:2020-10-29 11:26:08 【问题描述】:

我正在尝试按元素设置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 循环,并使用矩阵大小,将迭代次数转换为行和列索引。 某种形式的“压缩”迭代,对象包含或计算相应的索引。

然而, 这些对我来说似乎相当笨拙且容易出错,因为它们需要使用矩阵大小,甚至需要手动处理索引。 我正在寻找一种更简洁(可能是内部优化)的解决方案。我觉得应该有一种方法可以实现这一目标......

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

【问题讨论】:

【参考方案1】:

查看犰狳源代码,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;

【讨论】:

这正是我要找的,感谢您深入研究源代码!它似乎至少从 9.900.x 开始就可用了——我想知道,为什么它不属于 official docs...【参考方案2】:

您似乎已经自己回答了您的问题。我希望犰狳为我们提供了一个.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::SizeMatnum_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 的第一个参数。

【讨论】:

谢谢,我不知道arma::ind2sub,它解决了我建议的变通办法的大部分问题。我想这回答了这个问题。 :) — 正如您似乎也希望这样的功能:您知道这是否故意丢失?如果没有,可能值得尝试实施并打开 MR ... 我不知道这是否是故意遗漏的。如果你有兴趣,你的犰狳似乎托管在gitlab。

以上是关于遍历 arma::mat 并检索元素位置的主要内容,如果未能解决你的问题,请参考以下文章

(Rcpp, armadillo) 将 arma::vec 转换为 arma::mat

使用 std::nth_element 对 arma::mat 的行进行排序

使用 BeautifulSoup 遍历 html 树中的元素,并生成保持每个元素相对位置的输出?在 Python 中

javascript 循环遍历具有相同类的所有元素并更改子的位置

在 for 循环中获取 arma::mat 矩阵的每一行作为 arma::vec

将 arma::cx_mat 转换为数组数组