C# 创建线性化二维阵列的子阵列

C# 创建线性化二维阵列的子阵列,c#,arrays,unity3d,C#,Arrays,Unity3d,我确信这个解决方案比我想象的要简单,但出于某种原因,我无法理解它 我正在使用包含2d或3d数据的线性化(一维)阵列。具体来说,我在Unity DOTS环境中使用NativeArray,但我确信有一个通用的解决方案 以下是我的伪代码用例: origin[] = { 3, 4, 5, 9, 8, 7, 2, 1, 6 } originSize = (3, 3) 现在我想创建一个位置(1,1)的子数组,该数组的大小为(2,2)。 我希望得到 subarray[] = { 8, 7,

我确信这个解决方案比我想象的要简单,但出于某种原因,我无法理解它

我正在使用包含2d或3d数据的线性化(一维)阵列。具体来说,我在Unity DOTS环境中使用NativeArray,但我确信有一个通用的解决方案

以下是我的伪代码用例:

origin[] = {
  3, 4, 5,
  9, 8, 7,
  2, 1, 6
}

originSize = (3, 3)
现在我想创建一个位置(1,1)的子数组,该数组的大小为(2,2)。 我希望得到

subarray[] = {
  8, 7,
  1, 6
}
我当前的代码如下所示:

for loop over subarray with index...

int x = index % subSize.x;
int y = index / subSize.x;
int tileX = x + subPos.x * subSize.x;
int tileY = y + subPos.y * subSize.y;
int originIndex = tileX + tileY * originSize.x
subArray[index] = originArray[inputIndex];
这不仅会在某些输入中遇到越界问题,而且速度相当慢(这是代码的性能关键部分)。我希望有一个memcopy替代方案,但由于数据在数组中是碎片化的,我唯一的想法是逐行进行,这似乎也不是很快

我试图找到提取子数组的一般解决方案,但找不到任何不使用多维数组或锯齿数组的解决方案。重要的是,该解决方案适用于线性阵列且速度快


谢谢大家!

这是一段我尝试过并为我工作过的代码片段。如果有帮助,请告诉我: `

//原始数组的大小
int-originSizeX=4;
int-originSizeY=4;
//子数组的大小
int-subarsizex=3;
int-subArrSizeY=3;
//子数组在原始数组中的起始位置
int startingPosX=0;
int StartingPosY=1;
//创建原始数组
int[]arr=CreateArr(originSizeX,originSizeY);
//获取子数组
int[]subar=getsubar(arr,subArrSizeX,subArrSizeY,startingPosX,StartingPosY,originSizeX,originSizeY);
私有静态int[]getsubar(int[]arr,int-subArrSizeX,int-subArrSizeY,int-startingPosX,int-startingPosY,int-originArrSizeX,int-originArrSizeY)
{
int[]subar=新int[subArrSizeX*subArrSizeY];
int subarrcurrentinexx=0;
int subarrcurrentinexy=0;
对于(int originarcurrentindexy=startingPosY;originarcurrentindexy

`

我想这样的东西应该可以

public static class ArrayExtensions
{
    public static T[] GetSubArray<T>( this T[] origin, int originDimensionsX, int originDimensionsY, int startPositionX, int startPositionY, int targetDimensionsX, int targetDimensionsY)
    {
        // First of all some checks
        if(origin == null) return null;
        if(origin.Length == 0) return new T[0];
        if(originDimensionsX < 0 || originDimensionsY < 0 || originDimensionsX * originDimensionsY != origin.Length) throw new ArgumentOutOfRangeException($"Given dimensions {originDimensionsX},{originDimensionsY} do not match the given array length {origin.Length}!");
        if(startPositionX < 0 || startPositionX > originDimensionsX - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionX} is outside of the origin dimensions {originDimensionsX}!");
        if(startPositionY < 0 || startPositionY > originDimensionsY - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionY} is outside of the origin dimensions {originDimensionsY}!");
        if(targetDimensionsX < 0 || targetDimensionsY < 0) throw new ArgumentOutOfRangeException ("TargetDimensions may not be negative!");
        if(startPositionX + targetDimensionsX > originDimensionsX || startPositionY + targetDimensionsY > originDimensionsY) throw new ArgumentOutOfRangeException ($"Given TargetDimensions {targetDimensionsX},{targetDimensionsY} starting at {startPositionX},{startPositionY} does not fit into originDimensions {originDimensionsX},{originDimensionsY}!");

        var output = new T[targetDimensionsX * targetDimensionsY];

        var subIndex = 0;
        for(var y = startPositionY; y < startPositionY + targetDimensionsY; y++)
        {
            for(var x = startPositionX; x < startPositionX + targetDimensionsX; x++)
            {
                output[subIndex++] = origin[x + y * originDimensionsX];
            }
        }

        return output;
    }
}
会是

4, 5, 7, 8

由于对于X维我们总是为大型数组复制连续的值,因此使用
循环可能比使用内部的
更有效

public static T[] GetSubArray(this int[] origin, int originDimensionsX, int originDimensionsY, int startPositionX, int startPositionY, int targetDimensionsX, int targetDimensionsY)
    {
        // First of all some checks
        if(origin == null) return null;
        if(origin.Length == 0) return new T[0];
        if(originDimensionsX < 0 || originDimensionsY < 0 || originDimensionsX * originDimensionsY != origin.Length) throw new ArgumentOutOfRangeException($"Given dimensions {originDimensionsX},{originDimensionsY} do not match the given array length {origin.Length}!");
        if(startPositionX < 0 || startPositionX > originDimensionsX - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionX} is outside of the origin dimensions {originDimensionsX}!");
        if(startPositionY < 0 || startPositionY > originDimensionsY - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionY} is outside of the origin dimensions {originDimensionsY}!");
        if(targetDimensionsX < 0 || targetDimensionsY < 0) throw new ArgumentOutOfRangeException ("TargetDimensions may not be negative!");
        if(startPositionX + targetDimensionsX > originDimensionsX || startPositionY + targetDimensionsY > originDimensionsY) throw new ArgumentOutOfRangeException ($"Given TargetDimensions {targetDimensionsX},{targetDimensionsY} starting at {startPositionX},{startPositionY} does not fit into originDimensions {originDimensionsX},{originDimensionsY}!");

        var output = new T[targetDimensionsX * targetDimensionsY];

        var subIndex = 0;
        for(var y = startPositionY; y < startPositionY + targetDimensionsY; y++)
        {
            Array.Copy(origin, startPositionX + y * originDimensionsX, output, subIndex, targetDimensionsX);
            subIndex += targetDimensionsX;
        }

        return output;
    }
}


注意:在智能手机上键入->未测试,但我希望想法变得清晰

谢谢,这是可行的,但不幸的是速度非常慢。出于这个原因,我试图避免嵌套循环。如果没有其他办法,我将不得不处理它,但我仍然希望有更出色的表现。我将尝试调整您的算法,使其在Unity JobSystem的并行线程中工作得更好(在输出数据上具有连续索引的单循环),这可能已经提供了更好的性能。仍然非常感谢<代码>索引/子网站.xint
除法,code>将始终为0,不是吗?如果索引高于
subSize.x
(宽度),则不会。对于线性化2d阵列,这样的索引计算是非常正常的。索引介于0和
subSize.x*subSize.y之间。我认为这可能是迄今为止最好的答案,非常感谢。我需要检查我是否可以使用
NativeArray
执行
BlockCopy
或类似的操作,但是上面的解决方案已经非常好并且可以轻松地并行化(通过将工作拆分为块,因为它只依赖于子索引).噢,对于本机数组,您可能也可以使用它,它同样是通用的,您不需要知道字节大小谢谢,我完全错过了
Copy
方法。我主要使用
CopyFrom
CopyTo
方法,这些方法没有变量来指定要复制的部分。这很有帮助!
4, 5, 7, 8
public static T[] GetSubArray(this int[] origin, int originDimensionsX, int originDimensionsY, int startPositionX, int startPositionY, int targetDimensionsX, int targetDimensionsY)
    {
        // First of all some checks
        if(origin == null) return null;
        if(origin.Length == 0) return new T[0];
        if(originDimensionsX < 0 || originDimensionsY < 0 || originDimensionsX * originDimensionsY != origin.Length) throw new ArgumentOutOfRangeException($"Given dimensions {originDimensionsX},{originDimensionsY} do not match the given array length {origin.Length}!");
        if(startPositionX < 0 || startPositionX > originDimensionsX - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionX} is outside of the origin dimensions {originDimensionsX}!");
        if(startPositionY < 0 || startPositionY > originDimensionsY - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionY} is outside of the origin dimensions {originDimensionsY}!");
        if(targetDimensionsX < 0 || targetDimensionsY < 0) throw new ArgumentOutOfRangeException ("TargetDimensions may not be negative!");
        if(startPositionX + targetDimensionsX > originDimensionsX || startPositionY + targetDimensionsY > originDimensionsY) throw new ArgumentOutOfRangeException ($"Given TargetDimensions {targetDimensionsX},{targetDimensionsY} starting at {startPositionX},{startPositionY} does not fit into originDimensions {originDimensionsX},{originDimensionsY}!");

        var output = new T[targetDimensionsX * targetDimensionsY];

        var subIndex = 0;
        for(var y = startPositionY; y < startPositionY + targetDimensionsY; y++)
        {
            Array.Copy(origin, startPositionX + y * originDimensionsX, output, subIndex, targetDimensionsX);
            subIndex += targetDimensionsX;
        }

        return output;
    }
}
const int SIZEOF_INT = sizeof(int);

public static int[] GetSubArray(this int[] origin, int originDimensionsX, int originDimensionsY, int startPositionX, int startPositionY, int targetDimensionsX, int targetDimensionsY)
    {
        // First of all some checks
        if(origin == null) return null;
        if(origin.Length == 0) return new T[0];
        if(originDimensionsX < 0 || originDimensionsY < 0 || originDimensionsX * originDimensionsY != origin.Length) throw new ArgumentOutOfRangeException($"Given dimensions {originDimensionsX},{originDimensionsY} do not match the given array length {origin.Length}!");
        if(startPositionX < 0 || startPositionX > originDimensionsX - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionX} is outside of the origin dimensions {originDimensionsX}!");
        if(startPositionY < 0 || startPositionY > originDimensionsY - 1) throw new ArgumentOutOfRangeException($"Given startPosition {startPositionY} is outside of the origin dimensions {originDimensionsY}!");
        if(targetDimensionsX < 0 || targetDimensionsY < 0) throw new ArgumentOutOfRangeException ("TargetDimensions may not be negative!");
        if(startPositionX + targetDimensionsX > originDimensionsX || startPositionY + targetDimensionsY > originDimensionsY) throw new ArgumentOutOfRangeException ($"Given TargetDimensions {targetDimensionsX},{targetDimensionsY} starting at {startPositionX},{startPositionY} does not fit into originDimensions {originDimensionsX},{originDimensionsY}!");

        var output = new int[targetDimensionsX * targetDimensionsY];

        var subIndex = 0;
        for(var y = startPositionY; y < startPositionY + targetDimensionsY; y++)
        {
            // In this case the indices are all referring to bytes instead of array index
            Buffer.BlockCopy(origin, (startPositionX + y * originDimensionsX) * SIZEOF_INT, output, subIndex * SIZEOF_INT, targetDimensionsX * SIZEOF_INT);
            subIndex += targetDimensionsX;
        }

        return output;
    }
}