将1D编码的2D阵列划分为扇区

时间:2015-03-09 00:00:36

标签: c# arrays algorithm multidimensional-array

我将图像编码成一维颜色数组(为简单起见,这里用字母表示):

[A, B, C, D,
 E, F, G, H,
 I, J, K, L,
 M, N, O, P]

但是由于我使用的库的限制,每个图像必须在maxElements个项目和方块下。所以我需要做的是提取" sector"从那个图像,所以我可以分别迭代它们。 maxElements = 4的示例:

[A, B, [C, D,
 E, F]  G, H]
[I, J, [K, L,
 M, N]  O, P]

如果有余数,则应将其存储在较小的数组中。 side = 3maxElements = 4的示例:

[A, B, C,      [[A, B, [C,
 D, E, F,  ->    D, E]  F]
 G, H, I]       [G, H] [I]]

请注意,阵列是在第3列切割的,因为如果它的尺寸超过2x2,则会违反maxElements

然而,一个额外的挑战是我无法访问此图片,直到为时已晚,但我确实有图像的(如方方面)和每个扇区的最大元素数。所以我想要做的是为数组中的每个像素生成一个索引数组。

所以我有1D数组中每行的长度和行数(都是 side ),我需要为要获取的数据生成一个索引数组阵列。 side = 4maxElements = 4的示例输出:

[[1, 2, 5, 6], [3, 4, 7, 8], [9, 10, 13, 14], [11, 12, 15, 16]]

也许我没有睡觉太多时间,但我无法解决这个问题。

2 个答案:

答案 0 :(得分:0)

这是一个粗略的想法:

要访问2D数组的1D表示中的(x,y)元素:x + y*H。 假设我们想要在数组中访问x = 1和y = 2(W = 4,H = 4): arr[1 + 2*4] == arr[9] = J

由于我们知道如何通过坐标访问元素,我们可以使用循环:

for (int x = 0; x < W; x += 2) {
  for (int y = 0; y < H; y += 2)
    output[(x/2) + (y/2)*(H/2)] = new int[] { arr[x + y*H],     arr[(x+1) + y*H], 
                                          arr[x + (y+1)*H], arr[(x+1) + (y+1)*H] };
  }
}

这是草图。要处理side = 3 maxElements = 4案例,您需要检查边界,以检查(x+1)<W(y+1)<H。这意味着,有四种情况:

bool xi = (x+1)<W, yi = (y+1)<H;
if (xi && yi) // both within range
  output[...] = new int[] { arr[...], arr[...], arr[...], arr[...] };
if (!xi && yi) // only y within range
  output[...] = new int[] { arr[...], arr[...] };
if (xi && !yi) // only x within range
  output[...] = new int[] { arr[...], arr[...] };
else // both out of range
  output[...] = new int[] { arr[...] };

答案 1 :(得分:0)

回到这个问题后,我找到了解决方案:

public static List<List<int>> SectorizeMap<T>(IEnumerable<T> input, int width, int maxPerSector) {
    var sectorSide = (int)Math.Sqrt(maxPerSector);
    var widthSectors = (int)Math.Ceiling((float)width / sectorSide);
    var resultSectors = new List<List<int>>();

    for (var i = 0; i < input.Count(); i++) {
        var x = i % width;
        var y = i / width;
        var sectorX = x / sectorSide;
        var sectorY = y / sectorSide;
        var sectorIndex = sectorY * widthSectors + sectorX;
        if (resultSectors.Count <= sectorIndex) {
            resultSectors.Add (new List<int> ());
        }
        resultSectors[sectorIndex].Add(i);
    }
    return resultSectors;
}

使用以下示例:

var resultSectors = SectorizeMap(Enumerable.Range(0, 36), 6, 4);
Console.WriteLine(string.Join(", ", 
    resultSectors.Select(sec => string.Format("[{0}]", 
        string.Join(", ", sec)))));

工作原理

我们开始接收输入数组,宽度(以2D表示)和每个扇区的最大项目数。

  1. 由于扇区是正方形,因此请考虑每个扇区最大项目数的根,并将其用作扇区两边的维度。
  2. 计算一行中适合的扇区数。
  3. 迭代输入:
    1. 将元素的索引解码为(x,y)对。
    2. 将扇区(x,y)对分配给这些坐标
    3. 将扇区坐标转换为索引
    4. 将当前元素的索引添加到我们计算位置的扇区,并在必要时创建它。
  4. 返回部门列表。