簡體   English   中英

創建線性二維數組的子數組

[英]Creating sub-array of linearized 2d-array

我確信解決方案比我想象的要簡單,但由於某種原因,我無法理解它。

我正在使用包含 2d 或 3d 數據的線性化(一維)arrays。 具體來說,我在 Unity DOTS 環境中使用 NativeArrays,但我確信有一個通用的解決方案。

這是我的偽代碼用例:

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

originSize = (3, 3)

現在我想創建一個 position (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 替代方案,但由於數據在數組中是零散的,我唯一的想法是逐行 go,這似乎也不是很快。

我試圖找到提取子數組的通用解決方案,但找不到任何不使用多維或鋸齒狀 arrays 的解決方案。 該解決方案適用於線性 arrays 並且速度很快,這一點很重要。

謝謝!

這是我嘗試並為我工作的代碼片段。 讓我知道是否有幫助:`

        // Size for original array
        int originSizeX = 4;
        int originSizeY = 4;

        // Size for sub array
        int subArrSizeX = 3;
        int subArrSizeY = 3;

        // Starting positions of sub-array in original array
        int startingPosX = 0;
        int StartingPosY = 1;

        // Create original array
        int[] arr = CreateArr(originSizeX, originSizeY);

        // Get sub array
        int[] subArr = GetSubArr(arr, subArrSizeX, subArrSizeY, startingPosX, StartingPosY, originSizeX, originSizeY);


    private static int[] GetSubArr(int[] arr, int subArrSizeX, int subArrSizeY, int startingPosX, int startingPosY, int originArrSizeX, int originArrSizeY)
    {
        int[] subArr = new int[subArrSizeX * subArrSizeY];

        int subArrCurrentIndexX = 0;
        int subArrCurrentIndexY = 0;

        for (int originArrCurrentIndexY = startingPosY; originArrCurrentIndexY < startingPosY + subArrSizeY; originArrCurrentIndexY++)
        {
            for (int originArrCurrentIndexX = startingPosX; originArrCurrentIndexX < startingPosX + subArrSizeX; originArrCurrentIndexX++)
            {
                // Transform indices from 2D to 1D
                int originArrIndex = (originArrCurrentIndexY ) * originArrSizeX + originArrCurrentIndexX ;
                int subArrIndex = (subArrCurrentIndexY ) * subArrSizeX + subArrCurrentIndexX ;

                subArr[subArrIndex] = arr[originArrIndex];

                subArrCurrentIndexX++;

                if (subArrCurrentIndexX == subArrSizeX)
                {
                    subArrCurrentIndexX = 0;
                    subArrCurrentIndexY++;
                }
            }
        }

        return subArr;
    }

    private static int[] CreateArr(int originSizeX, int originSizeY)
    {
        int[] arr = new int[originSizeX * originSizeY];

        for (int i = 0; i < arr.Length; i++)
        {
            arr[i] = i;
        }

        return arr;
    }

`

我認為這樣的事情應該這樣做

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

例子

var origin = new []
{ 
    0, 1, 2, 
    3, 4, 5, 
    6, 7, 8
};  

var subArray = origin.GetSubArray(3, 3, 1, 1, 2, 2);

Debug.Log(string.Join(",", subArray));

將會

4, 5, 7, 8

因為對於X 維度,我們總是復制大 arrays 的連續值,它可能比使用內部for循環更有效

Array.Copy

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

或者你也可以 go 到字節級別並直接使用Buffer.BlockCopy (假設現在是 int 或其他 const 大小的基本類型數組 - 不是通用的,你需要知道你的類型的常量字節大小!)

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

注意:在智能手機上輸入 -> 未經測試,但我希望這個想法很清楚

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM