二维数组索引位置"触摸"

时间:2017-11-09 09:28:06

标签: c# .net arrays multidimensional-array

如果二维数组中的位置都是"触及"我想找到一种能够返回的方法。和类似的值,一路追踪。在我进入这个问题之前,有一个非常相似的问题,并解决here,但它是用python编写的,我对此一无所知。进一步扩展:

f f f f

f T T f

f T T f

f f f f  

[0][0]开始,它将返回该数组中的所有谬误,因为它们是相同的值并链回[0][0]

f f f T f f f

f T f T f T f

f f f T f f f

但基于此问题,从[0][0]开始只会返回[0][0,1,2][1][0,2][2][0,1,2]。但是如果你从[0][4]开始,那么它将返回[n][3]之后的所有谬误,因为它们与开始时的值相同,并且触及。

不是在寻找任何人来帮助我准确地编写代码,但可能会指出我正确的方向。请提前原谅我的新手级别,非常感谢你!

1 个答案:

答案 0 :(得分:1)

您似乎遇到了图形问题,而您正在寻找广度优先搜索或类似算法

  1. 图形节点:所有有效(f)数组项
  2. 图形边缘:当且仅当数组项是邻居
  3. 实现:

    private static IEnumerable<Tuple<int, int>> Touching(char[,] items, 
                                                         Tuple<int, int> startAt, 
                                                         char letter = 'f') {
      if (startAt.Item1 < 0 || startAt.Item1 >= items.GetLength(0) ||
          startAt.Item2 < 0 || startAt.Item2 >= items.GetLength(1))
        yield break; // or throw ArgumentOutOfRangeException
      else if (items[startAt.Item1, startAt.Item2] != letter)
        yield break;
    
      Queue<Tuple<int, int>> agenda = new Queue<Tuple<int, int>>();
      HashSet<Tuple<int, int>> visited = new HashSet<Tuple<int, int>>() { startAt };
    
      agenda.Enqueue(startAt);
    
      while (agenda.Any()) {
        for (int i = agenda.Count - 1; i >= 0; --i) {
          var point = agenda.Dequeue();
    
          yield return point;
    
          // Manhattan: left, right, top, bottom neighbors only, no diagonal ones
          var validNeighbors = new Tuple<int, int>[] {
             new Tuple<int, int>(point.Item1 - 1, point.Item2),     // left
             new Tuple<int, int>(point.Item1 + 1, point.Item2),     // right
             new Tuple<int, int>(point.Item1, point.Item2 - 1),     // top
             new Tuple<int, int>(point.Item1, point.Item2 + 1),}    // bottom
          .Where(p => p.Item1 >= 0 && p.Item1 < items.GetLength(0)) // Within array
          .Where(p => p.Item2 >= 0 && p.Item2 < items.GetLength(1)) // Within array
          .Where(p => items[p.Item1, p.Item2] == letter)            // valid point
          .Where(p => visited.Add(p));                              // not visited 
    
          foreach (var p in validNeighbors)
            agenda.Enqueue(p);
        }
      }
    }
    

    测试:

     char[,] data = new char[,] {
        { 'f', 'f', 'f', 'T', 'f', 'f', 'f',},
        { 'f', 'f', 'f', 'T', 'f', 'f', 'f',},
        { 'f', 'f', 'f', 'T', 'f', 'f', 'f',},
      };
    
      string report = string.Join(Environment.NewLine, 
        Touching(data, new Tuple<int, int>(0, 0), 'f'));
    
      Console.WriteLine(report);
    

    结果(以下所有这些项目都在触及startAt点<{1}}点 - (0, 0)):

    (0, 0)
    (1, 0)
    (0, 1)
    (2, 0)
    (1, 1)
    (0, 2)
    (2, 1)
    (1, 2)
    (2, 2)
    

    Linq 的帮助下,您可以以不同的方式组织报告(如问题中所示):

    var report = string.Join(Environment.NewLine, 
      Touching(data, new Tuple<int, int>(0, 0), 'f')
        .GroupBy(item => item.Item1, item => item.Item2)
        .OrderBy(chunk => chunk.Key)
        .Select(chunk => $"[{chunk.Key}][{string.Join(", ", chunk.OrderBy(x => x))}]"));
    

    并在下面做出回应:

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