不使用循环切割矩阵的行

发布于 2024-09-14 19:45:00 字数 65 浏览 6 评论 0原文

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

I have a matrix and i want to create a new matrix which will be the old matrix, but without the first row and first column. is there a way to do this without using loops?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

多情出卖 2024-09-21 19:45:00

我想创建一个新的矩阵

由此看来,您想要一个新的 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 的想法(及其警告)并使用 不安全的代码本质上模拟一个T[,],其索引指向原始矩阵的元素。想想看,您甚至可以在不诉诸不安全代码的情况下实现这一点;您只需要为您想要公开的功能定义一个接口(想到一个 this[int, int] 属性),然后实现该功能(您的返回类型不会在本例中是一个 T[,],但我想说的是它可能是类似的东西)。

i want to create a new matrix

From this it sounds to me like you want a new T[,] object.

which will be the old matrix, but without the first row and first column

I interpret this to mean you want the new T[,] object to contain the same values as the original, excepting the first row/column.

is there a way to do this without using loops?

If I've interpreted your question correctly, then no, not really. You will need to copy elements from one array to another; this requires enumeration. But that doesn't mean you can't abstract the implementation of this method into a reusable method (in fact, this is what you should do).

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

The above code isn't pretty, but once it's in place you'll be able to use it quite neatly:

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

Now, if I misinterpreted your question, and you are not dead-set on creating a new T[,] object, you can improve the efficiency of this approach by not allocating a new T[,] at all; you could take Abel's idea (along with its caveats) and use unsafe code to essentially simulate a T[,] with indices pointing to the elements of the original matrix. Come to think of it, you could even achieve this without resorting to unsafe code; you'd simply need to define an interface for the functionality you'd want to expose (a this[int, int] property comes to mind) and then implement that functionality (your return type wouldn't be a T[,] in this case, but what I'm getting at is that it could be something like it).

清眉祭 2024-09-21 19:45:00

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

但是,我强烈建议不要这样做。如果你这样做,你很有可能会搞砸类型并使垃圾收集器感到困惑。

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

Simply put: no. But if you do not use jagged arrays but instead use multi-dim arrays, and if you take some time to study the memory layout of arrays in .NET, you could do it with unsafe pointers and erasing a part of the memory and moving the starting pointer of the multi-dim array. But it'd be still dependent on how you design your arrays and your matrixes whether this works or not.

However, I'd highly advice against it. There's a big chance you screw up the type and confuse the garbage collector if you do so.

Alternatively, if you like to do this exercise, use C++/CLI for this task. In C++, you have more control and it's easier to manipulate memory and move pointers directly. You also have more control over the destructor and finalizers, which may come in handy here. But, that said, then you still need marshaling. If you'd do all this for performance, I'd advice to go back to the simple loops, it'll perform faster in most cases.

最近可好 2024-09-21 19:45:00

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

Matrix Library for .NET

Maybe you should have a look at using a maths library with good support for Matrix operations? Here's a thread which mentions a few:

Matrix Library for .NET

甜点 2024-09-21 19:45:00

使用 缓冲区 类,如果矩阵元素类型是基本类型,则可以进行逐行复制。这应该比逐元素复制更快。这是一个通用的扩展方法,演示了 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;
}

Using some methods from the Buffer class, you can do a row-wise copy if the matrix element type is a primitive type. This should be faster than an element-wise copy. Here is a generic extension method which demonstrates the use of 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文