C# 创建线性化二维阵列的子阵列
我确信这个解决方案比我想象的要简单,但出于某种原因,我无法理解它 我正在使用包含2d或3d数据的线性化(一维)阵列。具体来说,我在Unity DOTS环境中使用NativeArray,但我确信有一个通用的解决方案 以下是我的伪代码用例: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,
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的并行线程中工作得更好(在输出数据上具有连续索引的单循环),这可能已经提供了更好的性能。仍然非常感谢<代码>索引/子网站.x由于int
除法,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;
}
}