C#纠正2d数组作为子集2d数组的正确方法

时间:2016-03-08 21:57:50

标签: c# arrays

例如,如果我想对该数组中的元素进行迭代test和perfrorm操作,但必须以特定方式对其进行格式化。

基本上我试图使用2d数组遍历2d数组。

double[,] test = {
    {9, 8, 7, 6, 5, 4, 3, 2},
    {8, 7, 6, 5, 4, 3, 2, 1},
    {7, 6, 5, 4, 3, 2, 1, 0},
    {6, 5, 4, 3, 2, 1, 0, 0},
    {5, 4, 3, 2, 1, 0, 0, 0},
    {4, 3, 2, 1, 0, 0, 0, 0},
    {3, 2, 1, 0, 0, 0, 0, 0},
    {2, 1, 0, 0, 0, 0, 0, 0},
};

double[,] subset = new double[2,2]; //used in math

我希望能够做的是迭代任何大小的矩阵(假设它们的大小和方形均匀),每次迭代看起来像这样:

Iteration 1:
subset[0,0] = test[0,0];
subset[0,1] = test[0,1];
subset[1,0] = test[1,0];
subset[1,1] = test[1,1];

所以基本上它从大矩阵中选择了与子集相同的正方形。

Iteration 2:
subset[0,2] = test[0,2];
subset[1,2] = test[1,2];
subset[0,3] = test[0,3];
subset[1,3] = test[1,3];

3 个答案:

答案 0 :(得分:1)

您可以通过扩展方法执行此操作。一些值得一提的事情:

  • 使用Array.Copy而不是手动分配元素应该会产生更好的性能。
  • comment中提到的Tom A一样,您应该使用yield return来创建IEnumerable。然后,您可以使用foreach循环对其进行迭代,或执行其他操作。

<强>实施

static class MatrixExtensions
{
    public static IEnumerable<T[,]> ChunkMatrix<T>(this T[,] inputMatrix, int chunkWidth, int chunkHeight)
    {
        int inputWidth = inputMatrix.GetLength(0);
        int inputHeight = inputMatrix.GetLength(1);

        for(int i = 0; i < inputWidth; i += chunkWidth)
        {
            for(int j = 0; j < inputHeight; j += chunkHeight)
            {
                T[,] chunk = new T[chunkWidth, chunkHeight];
                for(int k = 0; k < chunkWidth; k++)
                {
                    int sourceIndex = i*inputWidth + k* inputWidth + j;
                    var destinationIndex = k* chunkHeight;
                    Array.Copy(inputMatrix, sourceIndex, chunk, destinationIndex, chunkHeight);
                }
                yield return chunk;
            }
        }
    }
}

<强>用法:

double[,] test = {
    {1,  2,  3,  4,  5,  6,  7,  8},
    {9,  10, 11, 12, 13, 14, 15, 16},
    {17, 18, 19, 20, 21, 22, 23, 24},
    {25, 26, 27, 28, 29, 30, 31, 32},
    {33, 34, 35, 36, 37, 38, 39, 40},
    {41, 42, 43, 44, 45, 46, 47, 48},
    {49, 50, 51, 52, 53, 54, 55, 56},
    {57, 58, 59, 60, 61, 62, 63, 64},
};

foreach(double[,] chunk in test.ChunkMatrix(2, 2))
{
    // First iteration:
    // 1 2
    // 9 10
    // 
    // Second iteration:
    // 3 4
    // 11 12
    //
    // ...
}

我将测试数据更改为不包含重复值,以便更好地说明效果。

应该注意的是,我的实现将无法在尺寸不是块的倍数的矩阵上正常工作。尺寸,正如评论中提到的那样,情况永远不会如此。如果需要,修改它以考虑这种情况不应该太难。

答案 1 :(得分:0)

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        const int COLUMNS = 8;
        const int ROWS = 8;
        const int SIZE = 2;
        static void Main(string[] args)
        {
            double[,] test = {
                {9, 8, 7, 6, 5, 4, 3, 2},
                {8, 7, 6, 5, 4, 3, 2, 1},
                {7, 6, 5, 4, 3, 2, 1, 0},
                {6, 5, 4, 3, 2, 1, 0, 0},
                {5, 4, 3, 2, 1, 0, 0, 0},
                {4, 3, 2, 1, 0, 0, 0, 0},
                {3, 2, 1, 0, 0, 0, 0, 0},
                {2, 1, 0, 0, 0, 0, 0, 0},
            };

            for (int i = 0; i < COLUMNS; i += SIZE)
            {
                for (int j = 0; j < ROWS; j += SIZE)
                {
                    for (int k = j; k < j + SIZE; k++)
                    {
                        for (int l = i; l < i + SIZE; l++)
                        {
                            Console.WriteLine("test[{0}, {1}] = {2}", k, l, test[k, l]);
                        }
                    }
                }
            }
            Console.ReadLine();
        }
    }
}

答案 2 :(得分:0)

我并不是说这是最好的解决方案,但是当我查看yield语句时,我设法让它使用此方法。

public static double[,] GetMapSection(Rectangle area, double[,] map) {
    double[,] result = new double[area.Width, area.Height];

    for (Int32 y = 0; y < area.Height; ++y) {
        for (Int32 x = 0; x < area.Width; ++x) {
            result[x, y] = map[x + area.X, y + area.Y];
        }
    }
    return result;
}

我通过以下方式致电:

List<double[,]> testChannel = new List<double[,]>();
for (int i = 0; i < Math.Sqrt(large_mapdata.Length); i+=8) {            
    for (int j = 0; j < Math.Sqrt(large_mapdata.Length); j+=8) {
        testChannel.Add(GetMapSection(new Rectangle(i, j, 8, 8), large_mapdata));
    }
}

在这个例子中,我从一个32x32大小的数组中创建8x8块。 我可以确认这对我有用,并且比以前更清洁。