【问题标题】:Cut rows of a matrix without using loops在不使用循环的情况下剪切矩阵的行
【发布时间】:2010-08-18 08:51:52
【问题描述】:

我有一个矩阵,我想创建一个新矩阵,它将是旧矩阵,但没有第一行和第一列。有没有办法在不使用循环的情况下做到这一点?

【问题讨论】:

    标签: c# matrix


    【解决方案1】:

    我想创建一个新矩阵

    我觉得你想要一个新的T[,] 对象。

    这将是旧矩阵,但没有第一行和第一列

    我将此解释为您希望新的 T[,] 对象与原始对象包含相同的值,但第一行/列除外。

    有没有办法在不使用循环的情况下做到这一点?

    如果我正确地解释了您的问题,那么不,不是真的。您需要将元素从一个数组复制到另一个数组;这需要枚举。但这并不意味着您不能将此方法的实现抽象为可重用的方法(实际上,这是您应该做的)。

    public static T[,] SubMatrix(this T[,] matrix, int xstart, int ystart)
    {
        int width = matrix.GetLength(0);
        int height = matrix.GetLength(1);
    
        if (xstart < 0 || xstart >= width)
        {
            throw new ArgumentOutOfRangeException("xstart");
        }
        else if (ystart < 0 || ystart >= height)
        {
            throw new ArgumentOutOfRangeException("ystart");
        }
    
        T[,] submatrix = new T[width - xstart, height - ystart];
    
        for (int i = xstart; i < width; ++i)
        {
            for (int j = ystart; j < height; ++j)
            {
                submatrix[i - xstart, j - ystart] = matrix[i, j];
            }
        }
    
        return submatrix;
    }
    

    上面的代码并不漂亮,但是一旦到位,你就可以非常巧妙地使用它:

    T[,] withoutFirstRowAndColumn = originalMatrix.SubMatrix(1, 1);
    

    现在,如果我误解了您的问题,并且您没有死心塌地创建一个新的 T[,] 对象,您可以通过不分配新的 T[,] 来提高这种方法的效率一点也不;您可以使用Abel's idea(连同它的注意事项)并使用unsafe 代码基本上模拟一个T[,],其索引指向原始矩阵的元素。想想看,你甚至可以在不诉诸unsafe 代码的情况下实现这一点;您只需要为要公开的功能定义一个接口(想到 this[int, int] 属性),然后实现该功能(在这种情况下,您的返回类型不会是 T[,],但是我的意思是它可能是类似的东西)。

    【讨论】:

    • +1,很好地涵盖了主题(感谢您的指点;)
    【解决方案2】:

    简单地说:没有。但是,如果您不使用交错数组而是使用多维数组,并且如果您花一些时间研究 .NET 中数组的内存布局,您可以使用不安全指针并擦除部分内存并移动多维数组的起始指针。但它仍然取决于你如何设计你的数组和你的矩阵是否有效。

    但是,我强烈反对它。如果这样做,您很有可能会搞砸类型并混淆垃圾收集器。

    或者,如果您喜欢做这个练习,可以使用 C++/CLI 来完成这个任务。在 C++ 中,您拥有更多控制权,并且更容易直接操作内存和移动指针。您还可以更好地控制析构函数和终结器,这可能在这里派上用场。但是,话虽如此,那么您仍然需要编组。如果你为了性能而做所有这些,我建议回到简单的循环,它在大多数情况下会执行得更快。

    【讨论】:

    • 我可以用循环来做到这一点,但我只是想知道是否有一种优雅的方式来做到这一点......
    • @aharont:不幸的是,没有。除非在速度优化的本机代码中,您需要执行数万亿次矩阵运算,并且值得每毫秒挤出一次。但是所有其他解决方案,即使是那些不看起来像循环的解决方案,都将使用循环和复制来实现(PS:有些人认为这很优雅......)。
    【解决方案3】:

    也许您应该看看使用对矩阵运算有良好支持的数学库?这是一个线程,其中提到了一些:

    Matrix Library for .NET

    【讨论】:

      【解决方案4】:

      使用Buffer 类中的一些方法,如果矩阵元素类型是原始类型,您可以进行逐行复制。这应该比按元素复制要快。下面是一个通用的扩展方法,演示了 Buffer 的使用:

      static PrimitiveType[,] SubMatrix<PrimitiveType>(
          this PrimitiveType[,] matrix, int fromRow, int fromCol) where PrimitiveType: struct
      {
          var (srcRowCount, srcColCount) = ( matrix.GetLength(0), matrix.GetLength(1) );
          if (fromRow < 0 || fromRow > srcRowCount)
          {
              throw new IndexOutOfRangeException(nameof(fromRow));
          }
          if (fromCol < 0 || fromCol > srcColCount)
          {
              throw new IndexOutOfRangeException(nameof(fromCol));
          }            
          var (dstRowCount, dstColCount) = ( srcRowCount - fromRow, srcColCount - fromCol );
          var subMatrix = new PrimitiveType[dstRowCount, dstColCount];
          var elementSize = Buffer.ByteLength(matrix) / matrix.Length;
          for (var row = 0; row < dstRowCount; ++row)
          {
              var srcOffset = (srcColCount * (row + fromRow) + fromCol) * elementSize;
              var dstOffset = dstColCount * row * elementSize;
              Buffer.BlockCopy(matrix, srcOffset, subMatrix, dstOffset, dstColCount * elementSize);
          }
          return subMatrix;
      }
      

      【讨论】:

        猜你喜欢
        • 2020-05-12
        • 1970-01-01
        • 2014-05-01
        • 1970-01-01
        • 2021-11-04
        • 1970-01-01
        • 2010-10-28
        • 1970-01-01
        • 2023-03-03
        相关资源
        最近更新 更多