如何在不复制的情况下将1-D阵列调整为C#中的2-D阵列?

时间:2022-09-06 12:14:22

As far as I know, a 2-D array is laid out in memory exactly like a 1-D array, it just uses different indexing. So given that, it seems like there must be some way (probably unsafe) in C# to convert a 1-D array to a 2-D array without actually copying elements, assuming you want the elements from the 1-D array to translate to the 2-D array in a row-first manner. I did figure out how to accomplish this with a single copy command, but it still seems like more processing than is necessary:

据我所知,二维数组在内存中的布局与一维数组完全相同,只是使用不同的索引。所以考虑到这一点,似乎在C#中必须有某种方式(可能是不安全的)将1-D数组转换为2-D数组而不实际复制元素,假设您希望将1-D数组中的元素转换为第一行中的二维数组。我确实弄清楚如何使用单个复制命令完成此操作,但它似乎仍然需要更多处理:

int[] onedim = new int[] { 5, 3, 6, 2, 1, 5 };
int[,] twodim = new int[2, 3];
GCHandle pinnedArray = GCHandle.Alloc(twodim, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
Marshal.Copy(onedim, 0, pointer, onedim.Length);
pinnedArray.Free();

Is there some way that I could tell C#, treat this 1-D array as a 2-D array with these dimensions instead? Unsafe code is fine. If not, is this a limitation of the language or is there some fundamental problem I am missing?

有什么方法可以告诉C#,将这个1-D阵列视为具有这些尺寸的2-D阵列?不安全的代码很好。如果没有,这是语言的限制还是我缺少一些基本问题?

3 个解决方案

#1


2  

One way would be to define a class that accesses the underlying 1D array

一种方法是定义访问底层1D数组的类

public class Array2D<T>
{
    private readonly T[] _data;
    private readonly Int32 _dimX;
    private readonly Int32 _dimY;

    public Array2D(T[] data, Int32 dimX, Int32 dimY)
    {
        _data = data;
        _dimX = dimX;
        _dimY = dimY;
    }

    public T this [Int32 x, Int32 y]
    {
        get { return _data[x * _dimY + y]; }
        set { _data[x * _dimY + y] = value; }
    }
}

var array = new[] { 1, 2, 3, 4, 5, 6 };
var array2d = new Array2D<Int32>(array, 2, 3);

Assert.AreEqual(array2d[0, 0], array[0]);
Assert.AreEqual(array2d[0, 1], array[1]);
Assert.AreEqual(array2d[0, 2], array[2]);
Assert.AreEqual(array2d[1, 0], array[3]);
Assert.AreEqual(array2d[1, 1], array[4]);
Assert.AreEqual(array2d[1, 2], array[5]);

My indexing might be backwards, however this wold behave like a 2D array while maintaining the 1D array reference.

我的索引可能是向后的,但是这个wold在保持1D数组引用的同时表现得像2D数组。

edit: Indexing was backwards, fixed it.

编辑:索引向后,修复它。

#2


0  

You could try to use the Buffer.BlockCopy method instead:

您可以尝试使用Buffer.BlockCopy方法:

Buffer.BlockCopy(onedim, 0, twodim, 0, onedim.Length * sizeof(int));

It accepts multidimensional arrays as well.

它也接受多维数组。

#3


-1  

Use Marshal.PtrToStructure.

使用Marshal.PtrToStructure。

I couldn't figure out how to do it without wrapping the 2d array in structure, but the following works without a copy.

如果没有在结构中包装2d数组,我无法弄清楚如何做到这一点,但以下工作没有副本。

    struct array2d 
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        int[,] data;
    };


    static void Main(string[] args)
    {

        int[] onedim = new int[] { 5, 3, 6, 2, 1, 5 };

        array2d twoDim;

        unsafe
        {
            fixed (int* p = onedim)
            {
                twoDim = Marshal.PtrToStructure<array2d>(new IntPtr(p));
            }
        }

    }

#1


2  

One way would be to define a class that accesses the underlying 1D array

一种方法是定义访问底层1D数组的类

public class Array2D<T>
{
    private readonly T[] _data;
    private readonly Int32 _dimX;
    private readonly Int32 _dimY;

    public Array2D(T[] data, Int32 dimX, Int32 dimY)
    {
        _data = data;
        _dimX = dimX;
        _dimY = dimY;
    }

    public T this [Int32 x, Int32 y]
    {
        get { return _data[x * _dimY + y]; }
        set { _data[x * _dimY + y] = value; }
    }
}

var array = new[] { 1, 2, 3, 4, 5, 6 };
var array2d = new Array2D<Int32>(array, 2, 3);

Assert.AreEqual(array2d[0, 0], array[0]);
Assert.AreEqual(array2d[0, 1], array[1]);
Assert.AreEqual(array2d[0, 2], array[2]);
Assert.AreEqual(array2d[1, 0], array[3]);
Assert.AreEqual(array2d[1, 1], array[4]);
Assert.AreEqual(array2d[1, 2], array[5]);

My indexing might be backwards, however this wold behave like a 2D array while maintaining the 1D array reference.

我的索引可能是向后的,但是这个wold在保持1D数组引用的同时表现得像2D数组。

edit: Indexing was backwards, fixed it.

编辑:索引向后,修复它。

#2


0  

You could try to use the Buffer.BlockCopy method instead:

您可以尝试使用Buffer.BlockCopy方法:

Buffer.BlockCopy(onedim, 0, twodim, 0, onedim.Length * sizeof(int));

It accepts multidimensional arrays as well.

它也接受多维数组。

#3


-1  

Use Marshal.PtrToStructure.

使用Marshal.PtrToStructure。

I couldn't figure out how to do it without wrapping the 2d array in structure, but the following works without a copy.

如果没有在结构中包装2d数组,我无法弄清楚如何做到这一点,但以下工作没有副本。

    struct array2d 
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        int[,] data;
    };


    static void Main(string[] args)
    {

        int[] onedim = new int[] { 5, 3, 6, 2, 1, 5 };

        array2d twoDim;

        unsafe
        {
            fixed (int* p = onedim)
            {
                twoDim = Marshal.PtrToStructure<array2d>(new IntPtr(p));
            }
        }

    }