如何根据C#中矩形数组中的特定值检查特定单元格的周围单元格

时间:2017-07-12 08:53:49

标签: c# arrays loops multidimensional-array

我使用以下方法根据给定索引(行和列)检查特定单元格周围的单元格(如果它是否为零),请参阅此数组:

enter image description here

我需要检查零周围(水平,垂直或对角)的单元格可以位于第一行,最后一行,第一列,最后一列或其间,即它可以是矩形阵列中的任何单元格,具体取决于到传递给方法的“rowIndex”和“colIndex”。

static Boolean TestZero(int[,] array,int colIndex, int rowIndex)
{                 
    /*Check Corners*/
    //First Corner
    if ((rowIndex == 0) && (colIndex == 0)) 
    {

        if (array[1, 0] == 1 || array[0, 1] == 1 || array[1, 1] == 1) return false;


    }

    //Second Corner
    if ((rowIndex == 0) && colIndex >= array.GetUpperBound(0))
    {

        if (array[array.GetUpperBound(0) - 1, 0] == 1 || array[array.GetUpperBound(0),1] == 1 || array[array.GetUpperBound(0)-1,1 ] == 1) return false;


    }

    //Third Corner
    if ((rowIndex >= array.GetUpperBound(1)) && (colIndex == 0))
    {

        if (array[0, array.GetUpperBound(1) - 1] == 1 || array[1, array.GetUpperBound(1)] == 1 || array[1, array.GetUpperBound(1)-1] == 1) return false;


    }

    //Fourth Corner
    if ((rowIndex >= array.GetUpperBound(1)) && (colIndex >= array.GetUpperBound(0)))
    {

        if (array[array.GetUpperBound(0), array.GetUpperBound(1) - 1] == 1 || array[array.GetUpperBound(0) - 1, array.GetUpperBound(1) - 1] == 1 || array[array.GetUpperBound(0) -1, array.GetUpperBound(1)] == 1) return false;


    }

    /* Check Boundries But Not Corners */
    //First Row 
    if ((rowIndex == 0) && (colIndex != array.GetUpperBound(0)) && (colIndex != 0))
    {

        for (int i = rowIndex; i <= rowIndex + 1; i++)
        {
            for (int j = colIndex - 1; j <= colIndex + 1; j++)
            {
                if ((i != rowIndex) && (j != colIndex))
                {
                    if (array[j,i] == 1) return false;
                }
            }
        }


    }

    //Last Row 
    if ((rowIndex >= array.GetUpperBound(1)) && (colIndex != array.GetUpperBound(0)) && (colIndex != 0))
    {

        for (int i = rowIndex; i <= rowIndex - 1; i--)
        {
            for (int j = colIndex - 1; j <= colIndex + 1; j++)
            {
                if ((i != rowIndex) && (j != colIndex))
                {
                    if (array[j,i] == 1) return false;
                }
            }
        }


    }

    //First & Last Columns 
    if ((rowIndex != array.GetUpperBound(1)) && ((rowIndex != 0)))
    {  
        //First column
       if(colIndex==0) 
       {
        for (int i = rowIndex-1; i <= rowIndex + 1; i++)
        {
            for (int j = colIndex; j <= colIndex + 1; j++)
            {
                if ((i != rowIndex) && (j != colIndex))
                {
                    if (array[j,i] == 1) return false;
                }
            }
        }

       }

        //Last Column
       if (colIndex == array.GetUpperBound(0)) 
       {
           for (int i = rowIndex -1; i <= rowIndex + 1; i++)
        {
            for (int j = colIndex; j <= colIndex - 1; j--)
            {
                if ((i != rowIndex) && (j != colIndex))
                {
                    if (array[j,i] == 1) return false;
                }
            }
        }

       }

    }

    /* In Between i.e. Not the Array Boundries */
    if(colIndex!=0 && colIndex != array.GetUpperBound(0) && rowIndex !=0 && rowIndex != array.GetUpperBound(1)) {

        for (int i = rowIndex - 1; i <= rowIndex + 1; i++)
           {
             for (int j = colIndex - 1; j <= colIndex + 1; j++)
               {
                if ((i != rowIndex) && (j != colIndex))
                  {
                  if (array[j,i] == 1) return false;
                  }
               }
           }

     } // end if statment
    return true;
 }  

我得到了一些错误的结果,我试图弄清楚问题,但我做不到!。

结果:

1-矩形阵列(遗传算法群体中的染色体):

enter image description here

2-我们需要检查周围环境的细胞的索引:

  

|(2,3)||(2,3)||(0,1)||(1,3)||(0,3)||(1,3)|

3-在每个预期细胞的至少一个周围细胞中含有零的阵列:

  

染色体0:真染色体1:真染色体2:假   染色体3:真染色体4:假染色体5:真实

任何帮助,以弄清楚为什么我得到一些错误的结果!!

4 个答案:

答案 0 :(得分:4)

从我所看到的,你的方法检查一个单元格是否被填充了1的单元格包围,如果是,则返回false。您的代码太复杂了,因为您试图将所有内容视为不同的情况,而不是通过它来使调试变得非常困难。以下方法是实现检查的更好方法的示例:

    bool TestZero(int[,] mat, int row, int col)
    {
        int ones = 0, cells = 0;//define counters

        //define bounderies
        int rowLen = Math.Min(row + 1, mat.GetLength(0) - 1),
            colLen = Math.Min(col + 1, mat.GetLength(1) - 1),
            rowIdx = Math.Max(0, row - 1),
            colIdx = Math.Max(0, col - 1);
        for (int i = rowIdx; i <= rowLen; i++)
        {
            for (int j = colIdx; j <= colLen; j++)
            {
                //if it is our given index, continue
                if (i == row && j == col)
                    continue;
                ++cells;//increment cells counter
                if (mat[i, j] == 1)//if the value of the cell is 1
                    ++ones;//increment the ones counter
            }
        }

        return ones < cells;//if there are less cells with '1' then 
                            //surrounding cells, return true.
    }

我们在这里做的是:

创建两个计数器:一个计算给定单元格周围的单元格数量,另一个计算围绕它的数量。

我们在变量中保存循环的bounderies:

  • rowLen:要访问的最后一行索引。它是给定单元格的行索引+ 1与矩阵中最后一行索引之间的较小值。
  • rowIdx:要在循环中检查的起始行索引。给定单元格的行索引-1与矩阵(0)中的第一行索引之间的值越大。
  • colLen:与rowLen相同,仅用于列。
  • colIdx:与rowIdx相同,仅用于列。

然后我们迭代我们用bounderies创建的迷你矩阵。对于每个单元格,如果不是我们给定的单元格,我们递增单元格计数器,如果它等于1,我们递增计数器。

最后,如果一个计数器小于单元格计数器,我们返回true,因为我们的单元格没有被1包围。

修改

如果并非所有周围单元格都包含1,则上面的示例返回true。 但是可以更改返回值以匹配不同的情况:

  • 如果您希望仅在包含true的0个单元格时返回1,请将返回行更改为以下内容:return ones == 0; 在这种情况下,单元格计数器是不必要的,只需要计数器。
  • 如果您只想在所有周围单元格包含true时返回1,请更改为以下内容:return ones == cells;

您基本上可以将返回值更改为您需要的任何情况,它非常灵活。

答案 1 :(得分:4)

与往常一样,编程时的第一条规则是:将问题分解为更小的位

我将使用 C#7 功能,只是为了它的乐趣。如果您不使用 C#7 ,请考虑将其翻译为以前的版本作为练习。

好的,第一步。你需要neigbouring细胞?好吧,让我们得到所有可能的相邻细胞,而不是关心它们是否存在。我们稍后会照顾好;记住,一次只有一个小问题。

private static bool IsValidCoordinate((int Row, int Column) coord, int rowCount, int columnCount)
{
    Debug.Assert(rowCount >= 0);
    Debug.Assert(columnCount >= 0);

    if (0 > coord.Row || coord.Row >= rowCount ||
        0 > coord.Column || coord.Column >= columnCount)
        return false;

    return true;
}

好的,现在我们有一个方法可以为我们提供所有可能的8个邻居。我返回它们的顺序是顺时针方向,从左上角开始。在这种情况下,顺序并不重要,因此请将其视为实施细节。

现在,我们需要检查任何给定的单元格是否有效。好吧,这似乎也很容易:

rowCount

好的,那也很简单。看看在简单方法中引入错误有多难?

另外,请注意方法开头的断言。此方法不适用于columnCountpublic static IEnumerable<T> GetNeighbouringCells<T>((int Row, int Column) coord, T[,] cells) { if (cells == null) throw new ArgumentOutOfRangeException(); if (!IsValidCoordinate(coord, cells.GetLength(0), cells.GetLength(1))) throw new ArgumentOutOfRangeException(); return GetAllNeighbouringCoordinates(coord.Row, coord.Column) .Where(c => IsValidCoordinate(c, cells.GetLength(0), cells.GetLength(1))) .Select(c => cells[c.Row, c.Column]); } 的无意义值,因此我在代码中强制执行。因为该方法是一个私有帮助器方法,我可以简单地断言,而不是抛出异常。如果断言在测试中失败,我知道我的代码中有一个错误。

现在,我们必须将两者结合在一起。让我们构建一个返回所有相邻单元格值的方法。我们将使用一些 LINQ 来删除难看的循环:

public static IEnumerable<(int Row, int Column)> CellsWithAtLeastOneNeighbourEqualTo<T>(
    this T[,] cells, T value)
{
    for (var row = 0; row < cells.GetLength(0); row++)
    {
        for (var column = 0; column < cells.GetLength(1); column++)
        {
            if (GetNeighbouringCells((row, column), cells).Any(c => c.Equals(value)))
            {
                yield return (row, column);
            }
        }
    }
}

你去了,现在你有一个简单的方法可以返回任何给定单元格的每个相邻值。

现在,您需要至少有一个相邻单元格为零的所有单元格?容易腻:

var cells = new[,] { { 0, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };
var n = cells.CellsWithAtLeastOneNeighbourEqualTo(0).ToList();

现在,如果你带一小段车:

[0, 1]
[1, 0]
[1, 1]

您将获得预期的结果:

{{1}}

答案 2 :(得分:1)

这似乎是一个简单的生活游戏计划。你不应该不经意地检查所有内容,而是使用一个函数来检查表中是否存在单元格的x和y坐标。

伪代码:

for each cell in celltable
    for each cell surrounding
        if cell index is valid && alive
            alive = alive + 1;
        endif
    endfor
    if alive is valid
       add cell to retList
    alive = 0;
endfor

没有人想调试巨大的if-else系统。

答案 3 :(得分:1)

性能不佳,但可以解决您的问题。

PS。请注意,我已将您的colIndexrowIndex重命名为xy

static bool TestZero(int[,] array, int x, int y)
    {
        try
        {
            if (array[x - 1, y - 1] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x, y - 1] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x + 1, y - 1] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x - 1, y] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x, y] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x + 1, y] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x - 1, y + 1] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x, y + 1] == 1) return false;
        }
        catch { }
        try
        {
            if (array[x + 1, y + 1] == 1) return false;
        }
        catch { }
        return true;
    }

我使用您的原始案例(您帖子中的第一张图片)进行测试,请使用以下代码。

private static int[,] array = { { 0, 0, 1, 1 }, { 0, 0, 0, 1 }, { 0, 1, 1, 1 }, { 1, 0, 1, 0 } };

    static void Main(string[] args)
    {
        for (int i = 0; i <= array.GetUpperBound(0); i++)
        {
            for (int j = 0; j <= array.GetUpperBound(1); j++)
            {
                Console.Write(TestZero(array, i, j) + " ");
            }
            Console.WriteLine();
        }
        Console.ReadKey();
    }

结果是

True False False False
False False False False
False False False False
False False False False

我要测试更多案例,但最后你可以尝试一下。