2016-03-08 56 views
0

对于一个例子,如果我想迭代从数组元素test和perfrorm操作,但它们具有以特定的方式进行格式化。C#正确的方式遍历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]; 
+1

可以编写利用'收率return'(https://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx)的扩展方法。基本上,扩展方法将迭代数组,并在每次迭代时在数组的子集上调用“yield return”。使用此功能,您可以自定义该子集中包含多大和哪些索引。有了这个说法,你可以使扩展方法更进一步,通过使用偏移量来跳过已经返回“yield return”的数组块,使每个“迭代”变得更加智能。 – Tom

+0

谢谢,我会去阅读它。 –

+0

如果我理解正确,你想在2x2(或者通常是'''''''m')子矩阵的“块”中迭代你的矩阵。如果父矩阵在任一方向上的大小不是所请求的子矩阵的维数的倍数,会发生什么?在你的例子中,你试图将一个8x8矩阵分块为2×2的子矩阵,但如果它是9x9,会发生什么? –

回答

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

在这个例子中我建立的8×8块出数组,它是在32×32大小的。 我可以证实这对我有效,比我以前清洁。

1

您可以通过扩展方法做到这一点。值得一提的几件事:

  • 使用Array.Copy而不是手动分配元素应该会产生更好的性能。
  • 像汤姆在comment提到的,你应该使用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 
    // 
    // ... 
} 

我改变了你的测试数据为不包括重复的值,以更好地说明效果。

应该指出,我的实现将不会在尺寸不是块尺寸的倍数的矩阵上正确工作,因为它在评论中提到,这绝不会是这种情况。如果需要,修改它以考虑这种情况应该不会太难。

+0

我们希望能找出我们即时使用的语言。感谢这个例子,这是C#非常酷的功能。 我不得不问。你会如何使用这种技术将零件重新组装在一起?假设它们的顺序相同,但在数值上略有改变。 –