C# 中任意等级数组的索引

发布于 2024-09-13 02:02:33 字数 324 浏览 6 评论 0原文

我需要迭代任意排名的数组。这适用于读取和写入,因此 GetEnumerator 将不起作用。

Array.SetValue(object, int) 不适用于多维数组。 Array.SetValue(object, params int[]) 需要过多的算术来迭代多维空间。它还需要动态调用来绕过签名的 params 部分。

我很想固定数组并用指针迭代它,但我找不到任何说明多维数组保证是连续的文档。如果它们在尺寸的末尾有填充,那么这是行不通的。我也希望避免不安全的代码。

有没有一种简单的方法可以仅使用单个索引来顺序寻址多维数组?

I need to iterate over an array of arbitrary rank. This is for both reading and writing, so GetEnumerator will not work.

Array.SetValue(object, int) doesn't work on multidimensional arrays.
Array.SetValue(object, params int[]) would require excessive arithmetic for iterating through the multidimensional space. It would also require dynamic invocation to get around the params part of the signature.

I'm tempted to pin the array and iterate over it with a pointer, but I can't find any documentation that says that multidimensional arrays are guaranteed to be contiguous. If they have padding at the end of a dimension then that won't work. I'd also prefer to avoid unsafe code.

Is there an easy way to sequentially address a multidimensional array using only a single index?

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

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

发布评论

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

评论(3

多彩岁月 2024-09-20 02:02:33

多维数组保证是连续的。来自 ECMA-335:

数组元素应按行主序排列在数组对象内(即,与最右侧数组维度关联的元素应从最低索引到最高索引连续排列)。

所以这有效:

int[,,,] array = new int[10, 10, 10, 10];

fixed (int* ptr = array)
{
    ptr[10] = 42;
}

int result = array[0, 0, 1, 0];  // == 42

Multidimensional arrays are guaranteed to be contiguous. From ECMA-335:

Array elements shall be laid out within the array object in row-major order (i.e., the elements associated with the rightmost array dimension shall be laid out contiguously from lowest to highest index).

So this works:

int[,,,] array = new int[10, 10, 10, 10];

fixed (int* ptr = array)
{
    ptr[10] = 42;
}

int result = array[0, 0, 1, 0];  // == 42
终陌 2024-09-20 02:02:33

您可以使用 RankGetUpperBound 属性/方法创建索引数组,并将其传递给数组的 SetValueGetValue< /code> 方法:

int[] Indices(Array a, int idx)
{
    var indices = new int[a.Rank];

    for (var i = 0; i < a.Rank; i++)
    {
        var div = 1;

        for (var j = i + 1; j < a.Rank; j++)
        {
            div *= a.GetLength(j);
        }

        indices[i] = a.GetLowerBound(i) + idx / div % a.GetLength(i);
    }

    return indices;
}

..并像这样使用它:

for (var i = 0; i < array.Length; i++)
{
    var indices = Indices(array, i);
    array.SetValue(i, indices);
    var val = array.GetValue(indices);
}

You can use the Rank and GetUpperBound property/method to create an indices array that you can pass to the array's SetValue and GetValue methods:

int[] Indices(Array a, int idx)
{
    var indices = new int[a.Rank];

    for (var i = 0; i < a.Rank; i++)
    {
        var div = 1;

        for (var j = i + 1; j < a.Rank; j++)
        {
            div *= a.GetLength(j);
        }

        indices[i] = a.GetLowerBound(i) + idx / div % a.GetLength(i);
    }

    return indices;
}

..and use it like so:

for (var i = 0; i < array.Length; i++)
{
    var indices = Indices(array, i);
    array.SetValue(i, indices);
    var val = array.GetValue(indices);
}
小嗲 2024-09-20 02:02:33

也许您可以将它们全部加入到一个临时集合中,然后对其进行迭代。

Perhaps you could join them all into the a single temporary collection, and just iterate over that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文