在不使用循环的情况下剪切矩阵的行

时间:2010-08-18 08:51:52

标签: c# matrix

我有一个矩阵,我想创建一个新矩阵,它将是旧矩阵,但没有第一行和第一列。有没有办法不使用循环呢?

4 个答案:

答案 0 :(得分: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[,]对象,则可以通过不分配新的{{}来提高此方法的效率完全{1}}您可以使用Abel's idea(及其警告)并使用T[,]代码来基本上模拟 unsafe,索引指向原始矩阵的元素。想想看,你甚至可以在不诉诸T[,]代码的情况下实现这一目标;你只需要为你想要公开的功能定义一个接口(一个unsafe属性),然后实现该功能(你的返回类型不是this[int, int] in这种情况,但我得到的是它可能是喜欢的东西。)

答案 1 :(得分:0)

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

但是,我强烈反对它。如果你这么做的话,很有可能搞砸了这种类型并混淆了垃圾收集器。

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

答案 2 :(得分:0)

也许你应该看看如何使用一个对Matrix操作有很好支持的数学库?这是一个提到一些的主题:

Matrix Library for .NET

答案 3 :(得分:0)

使用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;
}