【问题标题】:Removing zero rows from a Matrix (elegant way)从矩阵中删除零行(优雅的方式)
【发布时间】:2014-08-04 08:38:09
【问题描述】:

我有一个包含零行的矩阵。我想删除零行。矩阵为 Nx3。我所做的很简单。我创建std::vector,其中每三个元素代表一行,然后将其转换为Eigen::MatrixXd。有没有删除零行的优雅方法?

#include <iostream>
#include <vector>
#include <Eigen/Dense>



Eigen::MatrixXd VecToMat(const std::vector<double> vec)
{
    int rows(vec.size()/3) , cols(3);
    Eigen::MatrixXd temp( rows , cols);
    int count(0);
    for ( int i(0); i < rows; ++i)
    {
        temp(i,0) = vec[count]; 
        temp(i,1) = vec[count+1]; 
        temp(i,2) = vec[count+2]; 
        count += 3;
    }

    return temp;
}

Eigen::MatrixXd  getNewMat(Eigen::MatrixXd& Z)
{
    std::vector<double> vec;

    for ( int i(0); i < Z.rows(); ++i)
    {
        if ( (Z(i,0) && Z(i,1) && Z(i,2)) != 0 ){
            vec.push_back(Z(i,0));
            vec.push_back(Z(i,1));
            vec.push_back(Z(i,2));
        }
    }

    Eigen::MatrixXd temp = VecToMat(vec);

    return temp;
}

int main()
{
    Eigen::MatrixXd Z(5,3);
    Z.setOnes();


    Z(0,0) = 0;
    Z(0,1) = 0;
    Z(0,2) = 0;

    Z(1,0) = 0;
    Z(1,1) = 0;
    Z(1,2) = 0;

    Z(2,0) = 0;
    Z(2,1) = 0;
    Z(2,2) = 0;

    std::cout << Z << std::endl << std::endl;
    std::cout << getNewMat(Z) << std::endl;
    std::cin.get();
    return 0;
}

【问题讨论】:

  • 您要在程序的哪一点去除零?
  • @Velthune,你是什么意思?
  • 想要从 MatrixXd 或向量中删除零?
  • 来自矩阵。我用矢量来四处走动。但我猜这绝对不是一种优雅的方式。
  • 我看不出这个检查是如何工作的:(Z(i,0) &amp;&amp; Z(i,1) &amp;&amp; Z(i,2)) != 0。如果任何一个为 0,则应返回 false。如果你想变得棘手,你想要 ||,而不是 &amp;&amp;,或者你可以把它们全部写出来。或者寻找一种将行作为(数学)向量的方法,并将其与 0(数学)向量进行比较。

标签: c++ matrix eigen3


【解决方案1】:

这是一个我觉得非常优雅的完整实现。请注意,这个不保留非零规则的顺序,这可能不是您想要的,但在复杂性和代码行数方面更有效:

void removeZeroRows(Eigen::MatrixXd& mat)
{
  Matrix<bool, Dynamic, 1> empty = (mat.array() == 0).rowwise().all();

  size_t last = mat.rows() - 1;
  for (size_t i = 0; i < last + 1;)
  {
    if (empty(i))
    {
      mat.row(i).swap(mat.row(last));
      empty.segment<1>(i).swap(empty.segment<1>(last));
      --last;
    }
    else
      ++i;
  }
  mat.conservativeResize(last + 1, mat.cols());
}

【讨论】:

    【解决方案2】:

    基本上你可以遵循这样的伪代码:

    • 得到 N = 行,M = 列
    • 每个 N 迭代
    • 如果 N[0] = 0 迭代在第一个非零时退出的行
    • 如果 N[0] = 0 && .. && N[M] = 0
    • 删除行

    对于删除单行:

    void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove) {
        unsigned int numRows = matrix.rows() - 1;
        unsigned int numCols = matrix.cols();
        unsigned int rowPos = numRows - rowToRemove;
        if( rowToRemove < numRows ) {
            matrix.block(rowToRemove, 0, rowPos, numCols) = matrix.block(rowToRemove + 1, 0, rowPos,numCols);
        }
        matrix.conservativeResize(numRows, numCols);
    }
    

    【讨论】:

      【解决方案3】:

      将每个非空行保存到一个向量中,然后创建一个新矩阵

      vector<block> buffer; //not sure of the type name for the rows
      VectorXd zero(3); //or appropriate comparable type
      for(int i = 0; i < Z.rows(); i++){ //note: possibly a function call each time
          if(Z.row(i) != zero)
          //if((Z.row(i) != 0).any()) //broadcasting comparison?
              buffer.push_back(Z.row(i));
      }
      MatrixXd return_value(buffer.size(), 3);
      for(int i = buffer.size(); i --> 0;)
          return_value.row(i) = buffer[i];
      
      return return_value;
      

      警告:调整旧文件的大小而不是制作新文件可能会在保存之前删除内容。

      我无法从此处阅读文档,因此您必须亲自查看可以对块对象执行哪些比较操作。最后,尝试row.any()(更快?)或row.squaredNorm() == 0

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-28
        • 2014-10-21
        • 1970-01-01
        • 2019-10-08
        相关资源
        最近更新 更多