【发布时间】:2010-08-18 08:51:52
【问题描述】:
我有一个矩阵,我想创建一个新矩阵,它将是旧矩阵,但没有第一行和第一列。有没有办法在不使用循环的情况下做到这一点?
【问题讨论】:
我有一个矩阵,我想创建一个新矩阵,它将是旧矩阵,但没有第一行和第一列。有没有办法在不使用循环的情况下做到这一点?
【问题讨论】:
我想创建一个新矩阵
我觉得你想要一个新的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[,],但是我的意思是它可能是类似的东西)。
【讨论】:
简单地说:没有。但是,如果您不使用交错数组而是使用多维数组,并且如果您花一些时间研究 .NET 中数组的内存布局,您可以使用不安全指针并擦除部分内存并移动多维数组的起始指针。但它仍然取决于你如何设计你的数组和你的矩阵是否有效。
但是,我强烈反对它。如果这样做,您很有可能会搞砸类型并混淆垃圾收集器。
或者,如果您喜欢做这个练习,可以使用 C++/CLI 来完成这个任务。在 C++ 中,您拥有更多控制权,并且更容易直接操作内存和移动指针。您还可以更好地控制析构函数和终结器,这可能在这里派上用场。但是,话虽如此,那么您仍然需要编组。如果你为了性能而做所有这些,我建议回到简单的循环,它在大多数情况下会执行得更快。
【讨论】:
也许您应该看看使用对矩阵运算有良好支持的数学库?这是一个线程,其中提到了一些:
【讨论】:
使用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;
}
【讨论】: