首页 > 解决方案 > 存储为子数组的高性能连接二维数组

问题描述

想象一下,我们有几个由 XY 坐标标识的 3x3 2D 数组。

伪代码:

Array 0-0     Array 1-0
[[1,2,1]      [[1,2,1]  
 [2,3,2]       [2,3,2]
 [3,1,2]]      [3,1,2]]
 
Array 0-1     Array 1-1
[[1,2,1]      [[1,2,1]  
 [2,3,2]       [2,3,2]
 [3,1,2]]      [3,1,2]]

我们还有一个索引数组,用来索引所有这些子数组。

chunk_array = [
   [Array 0-0, Array 0-1],
   [Array 1-0, Array 1,1]
]

问题是如何快速创建一个包含所有子数组的 6x6 最终数组,而无需迭代数组的所有元素,因为这是一个非常关键的地方,必须在尽可能短的时间内运行。

所以问题:执行此操作的最快方法是什么?我看过缓冲区副本,但仍然不确定这里最好的方法是什么。

标签: c#

解决方案


这是基于评论中Alexei Levenkov建议的解决方案。从他的评论中:最快的做某事的方法是根本不做......这在你的情况下是否有效(即通过将所有 4 包装到一个类中,以你喜欢的方式公开索引)?

您创建四个单独的数组,然后将它们添加到能够将这些数组保存在矩形数组中的包装器中。我使用一个函数来访问各个元素,但是您可以使用索引器来代替(如果您倾向于那样 - 我不是,对于简单的索引器来说,该访问器似乎有点过于复杂)。

这是主要课程:

public class CompositeArray<T> where T:new()
{
    private readonly T[,][,] _componentArray = null;

    public int IndividualArrayWidth { get; }
    public int IndividualArrayHeight { get; }
    public int ComponentArrayWidth { get; }
    public int ComponentArrayHeight { get;  }
    public int OverallArrayWidth => IndividualArrayWidth * ComponentArrayWidth;
    public int OverallArrayHeight => IndividualArrayHeight * ComponentArrayHeight;

    public CompositeArray(int individualArrayWidth, int individualArrayHeight, int componentArrayWidth,
        int componentArrayHeight)
    {
        IndividualArrayWidth = individualArrayWidth;
        IndividualArrayHeight = individualArrayHeight;
        ComponentArrayWidth = componentArrayWidth;
        ComponentArrayHeight = componentArrayHeight;
        _componentArray = new T[ComponentArrayWidth, ComponentArrayHeight][,];
    }

    public void SetIndividualArray(int x, int y, T[,] array)
    {
        if (x < 0 || x >= IndividualArrayWidth)
        {
            throw new ArgumentOutOfRangeException(nameof(x), x, $@"Must be between 0 and {IndividualArrayWidth - 1}");
        }
        if (y < 0 || y >= IndividualArrayHeight)
        {
            throw new ArgumentOutOfRangeException(nameof(y), y, $@"Must be between 0 and {IndividualArrayHeight - 1}");
        }
        if (array.GetLength(0) != IndividualArrayWidth || array.GetLength(1) != IndividualArrayHeight)
        {
            throw new ArgumentOutOfRangeException(nameof(array),  $@"Must be between an array that is {IndividualArrayWidth} by {IndividualArrayHeight}");
        }

        _componentArray[x, y] = array;
    }

    public T GetOverallElement(int x, int y)
    {
        if (x < 0 || x >= OverallArrayWidth)
        {
            throw new ArgumentOutOfRangeException(nameof(x), x, $@"Must be between 0 and {OverallArrayWidth - 1}");
        }
        if (y < 0 || y >= OverallArrayHeight)
        {
            throw new ArgumentOutOfRangeException(nameof(y), y, $@"Must be between 0 and {OverallArrayHeight - 1}");
        }

        int whichArrayX = x / IndividualArrayWidth;
        int innerX = x % IndividualArrayWidth;
        int whichArrayY = y / IndividualArrayHeight;
        int innerY = y % IndividualArrayHeight;

        return (_componentArray[whichArrayX, whichArrayY][innerX, innerY]);
    }
}

请注意,我创建了一个矩形锯齿状矩形阵列。花了一点时间来弄清楚语法。

请注意,根本没有复制。您只需为每个元素访问支付两次整数除法和两次整数模运算。如果您只使用 2x2 数组,则可以将其减少为两个位移位和两个位测试(因为除以二是一个简单的位移位,并且检查偶数/奇数只是对最低有效位的测试)。

这是一些练习该类的代码:

 int[,] array00 = new int[,]
 {
     {1, 2, 3},
     {4, 5, 6},
     {7, 8, 9}
 };
 int[,] array01 = new int[,]
 {
     {11, 12, 13},
     {14, 15, 16},
     {17, 18, 19}
 };
 int[,] array10 = new int[,]
 {
     {21, 22, 23},
     {24, 25, 26},
     {27, 28, 29}
 };
 int[,] array11 = new int[,]
 {
     {31, 32, 33},
     {34, 35, 36},
     {37, 38, 39}
 };

 CompositeArray<int> bigArray = new CompositeArray<int>(array00.GetLength(0), array00.GetLength(1), 2,2);
 bigArray.SetIndividualArray(0, 0, array00);
 bigArray.SetIndividualArray(0, 1, array01);
 bigArray.SetIndividualArray(1, 0, array10);
 bigArray.SetIndividualArray(1, 1, array11);

 var shouldBe2 = bigArray.GetOverallElement(0, 1);
 var shouldBe6 = bigArray.GetOverallElement(1, 2);
 var shouldBe28 = bigArray.GetOverallElement(5, 1);
 var shouldBe16 = bigArray.GetOverallElement(1, 5);
 var shouldBe32 = bigArray.GetOverallElement(3, 4);

推荐阅读