【问题标题】:Changing my variable creates infinite loop更改我的变量会创建无限循环
【发布时间】:2019-02-25 03:01:41
【问题描述】:

我最近一直在学习 Python,但最近想做一个涉及 2D 数组的项目,所以我决定切换到 C#(如果我的代码很糟糕,请见谅)

基本上我正在编写一个为我做填字游戏的程序。

  • 我有 i 遍历顶部/底部
  • 我有 j 从左到右迭代

我找到第一个字母 i want - 我们称之为“keyletter”

现在我需要查看它周围的所有 8 个空间。如果i/j 的位置是[1,2],我会先查看[0,2]

在我的代码中,我想将 i1 更改为 0,然后打印(如果这是正确的字母)第二个字母是:[0,2]

当我将 i1 更改为 0 并尝试打印时,它会吐出一百万次并卡住。

public static void Main(string[] args)
{
    string keyLetter = "g";
    string keyLetter2 = "b";
    string[,] crossword = new string[,] 
    { 
        { "a", "b", "c", "d" },
        { "e", "f", "g", "h" }, 
        { "a", "e", "b", "c" }, 
        { "i", "j", "k", "l" }
    };

    for (int i = 0; i < crossword.GetLength(0); i++)
    {
        for (int j = 0; j < crossword.GetLength(1); j++)
        {
            if (keyLetter == crossword[i, j])
            {
                Console.Write(keyLetter + " is [" + i + ", " + j + "]");
                Console.WriteLine();
                Console.WriteLine();
                Console.Write("i is: " + i);
                Console.WriteLine();
                Console.Write("j is: " + j);
                Console.WriteLine();

                if (keyLetter2 == crossword[i - 1, j])
                {
                    // i--;
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i + 1, j])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                /*
                else if (keyLetter2 == crossword[i + 1, j - 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i, j - 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i - 1, j - 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i + 1, j + 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i, j + 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }
                else if (keyLetter2 == crossword[i - 1, j + 1])
                {
                    Console.Write("[i/j] position for " + keyLetter2 + " is [" + i + 
                        ", " + j + "]");
                }*/

                Console.WriteLine();
            }
        }
    }
}    

我的设置如下:

  • keyletter = "a"
  • keyletter2 = "b"

Loop problem picture

【问题讨论】:

  • keyletter,keyletter2是什么类型,填字数组是什么类型?
  • if (keyLetter2 == crossword[i-1, j]) 如果i == 0,你将抛出IndexOutOfRangeExceptioni == crossword.GetLength(0) - 1 时与 else if (keyLetter2 == crossword[i+1, j]) 相同的问题
  • 请您将您的代码简化为演示问题的最小示例吗?目前有很多被注释掉的代码,而且空行比要求的多,这使得阅读代码比需要的更难。
  • “发布一个完整的示例”和“发布带有大量注释掉的代码,使其难以阅读的代码”之间存在很大差异。提出问题时,最好考虑读者会发现什么有用。拥有重现问题的完整代码非常很有用,这样读者就可以自己运行它。拥有大量与问题无关的代码是有用的。编写问题时,请花一些时间将代码精简到演示问题所需的内容。这样做时,您通常会自己发现问题。
  • (最好使用一致的格式样式 - 目前混合了 2 空格缩进和 4 空格缩进,行尾大括号和单独大括号-line。理想情况下,以常用的 C# 样式进行格式化,即在单独的行上大括号,4 个空格缩进。如果您使用的是 Visual Studio,只需要求它重新格式化整个文档即可。)

标签: c#


【解决方案1】:

问题出在语句上

//if (keyLetter2 == crossword[i-1, j])

这里,如果矩阵是这样的

"

a b c

d e f

g h 我

"

并假设您要搜索模式“ba”,那么显然您将寻找 b,因此 i 将为 0,j 将为 1。现在,您将执行 (i-1),这将是 - 1(没有负索引),因此错误。

最好的方法是检查 i 或 j 是否已经为 0。如果它们是 0,那么你不需要 i-1 或 j-1,你可以像 " 如果(i!=0) 然后 if (keyLetter2 == 填字游戏[i-1, j]) ... "

【讨论】:

  • 此外,还要检查极端条件,例如 j 是否为最大值、i 为最大值或 j 为最小值或 i 为最小值
  • 好的,但是在我的代码中我正在搜索 g。这是故意在一切[1,2]的中间。然后我寻找 c,它不是 >0,因为 g 在中间。不要担心 -1 的事情。当我创建完整数组时,我将添加缓冲区索引。关键是我试图让 i = 1 到 i = 0。我只想说 - 关键字 2 在 [x,y] 就是这样!!!!!!
  • 现在是凌晨 2 点,我只是在做这个,所以我不必做这个愚蠢的西班牙语填字游戏。认为这会很有趣,但我需要尽快睡觉!
【解决方案2】:

我看不到任何无限循环,但在

出现运行时异常 (IndexOutOfRangeException)
if (keyLetter2 == crossword[i-1, j]) {...}      // if i == 0
...
else if (keyLetter2 == crossword[i+1, j]) {...} // if i == crossword.GetLength(0) - 1

让我们摆脱这些异常并刷新循环:

for (int i = 0; i < crossword.GetLength(0); ++i)
  for (int j = 0; j < crossword.GetLength(1); ++j)
    if (keyLetter == crossword[i, j]) {
      // Keep you messages being readable with a help of string interpolation - $""
      Console.WriteLine(string.Join(Environment.NewLine,
        $"{keyLetter} is [{i}, {j}]",
         ""
        $"i is: {i}",
         "" 
        $"j is: {j}",
         ""
      ));

      // Do not repeat yourself: if you want 4 neighbors to test
      for (int neighbor = 0; neighbor < 4; ++neighbor) {
        int ii = i + (neighbor % 2) * (neighbor - 1);
        int jj = j + (1 - neighbor % 2) * (neighbor - 1);

        // Check indexes ii, jj before addressing [ii, jj]
        if (ii >= 0 && ii < crossword.GetLength(0) &&
            jj >= 0 && jj < crossword.GetLength(1) && 
            keyLetter2 == crossword[ii, jj]) {
          Console.Write($"[i/j] position for {keyLetter2} is [{i}, {j}]");

          // In case we want at most one neighbor; comment it out if we want all of them
          break;
        }
      }
    }

如果你有8(不是4)邻居要检查

    ...
    bool found = false;

    for (int ii = Math.Max(0, i - 1); ii <= Math.Min(i + 1, crossword.GetLength(0)) && !found; ++ii) 
      for (int jj = Math.Max(0, j - 1); jj <= Math.Min(j + 1, crossword.GetLength(0)) && !found; ++jj) {
        if ((ii != i || jj != j) && keyLetter2 == crossword[ii, jj])) {
          Console.Write($"[i/j] position for {keyLetter2} is [{i}, {j}]");

          // In case we want at most one neighbor; comment it out if we want all of them 
          found = true;
        }
      }

【讨论】:

    【解决方案3】:

    我会采取稍微不同的方法,将“邻居搜索”委托给辅助方法。您可以将数组、应搜索其邻居的单元格以及要搜索的值传递给此方法。

    因为单元格项目由两个整数坐标定义,并且我们可以使用现有的Point 结构,它具有两个整数属性(XY),所以我使用它来表示一个单元格在我们的数组中。

    辅助函数的工作原理是通过从它的XY 值中减去1 来确定我们正在搜索其邻居的单元格周围的XY 的最小值。然后我们需要确保这个结果不小于0,以确保我们保持在数组的范围内。

    同样,我们添加1 以获得最大值,并确保它不大于数组的上限。

    最后,我们在List&lt;Point&gt; 中返回匹配列表(如果找到的话):

    public static List<Point> GetNeighborMatches(string[,] grid, Point item, string valueToFind)
    {
        var result = new List<Point>();
    
        // if our grid is empty or the item isn't in it, return an empty list
        if (grid == null || grid.Length == 0 ||
            item.X < 0 || item.X > grid.GetUpperBound(0) ||
            item.Y < 0 || item.Y > grid.GetUpperBound(1))
        {
            return result;
        }
    
        // Get min and max values of x and y for searching
        var minX = Math.Max(item.X - 1, 0);
        var maxX = Math.Min(item.X + 1, grid.GetUpperBound(0));
        var minY = Math.Max(item.Y - 1, 0);
        var maxY = Math.Min(item.Y + 1, grid.GetUpperBound(1));
    
        // Loop through all neighbors to find a match
        for (int x = minX; x <= maxX; x++)
        {
            for (int y = minY; y <= maxY; y++)
            {
                // Continue looping if we're on the 'item'
                if (x == item.X && y == item.Y) continue;
    
                // If this is a match, add it to our list
                if (grid[x, y] == valueToFind) result.Add(new Point(x, y));
            }
        }
    
        // Return all the matching neighbors
        return result;
    }
    

    现在我们可以在您现有的代码中使用这个辅助方法:

    public static void Main(string[] args)
    {
        string keyLetter = "g";
        string keyLetter2 = "b";
        string[,] crossword = new string[,]
        {
            { "a", "b", "c", "d" },
            { "e", "f", "g", "h" },
            { "a", "e", "b", "c" },
            { "i", "j", "k", "l" }
        };
    
        for (int i = 0; i < crossword.GetLength(0); i++)
        {
            for (int j = 0; j < crossword.GetLength(1); j++)
            {
                if (keyLetter == crossword[i, j])
                {
                    // we found a match for our first letter!
                    Console.WriteLine("The first value (" + keyLetter + ") is at [" + 
                        i + ", " + j + "]");
    
                    // get neighboring matches for keyLetter2
                    List<Point> matches = GetNeighborMatches(crossword, 
                        new Point(i, j), keyLetter2);
    
                    // Output our matches if we found any
                    if (matches.Any())
                    {
                        foreach (var match in matches)
                        {
                            Console.WriteLine("The second value (" + keyLetter2 + 
                                ") is at [" + match.X + ", " + match.Y + "]");
                        }
                    }
                    else
                    {
                        Console.WriteLine("No match was found for '" + keyLetter2 + 
                            "' near [" + i + ", " + j + "]");
                    }
                }
            }
        }
    }
    

    输出

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 2020-12-19
      • 1970-01-01
      • 2021-02-20
      • 2016-09-25
      • 2021-08-11
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      相关资源
      最近更新 更多