使用LINQ从多维数组中提取特定值

时间:2010-04-10 21:23:35

标签: c# linq

我正在处理boolint和各种struct的多维数组。代码循环遍历这些数组并对特定值执行某些操作。例如,

        for (int x = 0; x < this.Size.Width; x++) {
            for (int y = 0; y < this.Size.Height; y++) {
                if (this.Map[x, y]) {
                    DrawTerrain(this.Tile[x, y].Location, Terrain.Water);
                }
            }
        }

我可以做简单的LINQ,但我不能做我想做的事情。我想做的是使用LINQ。也许像是

from x in this.Map where x == true execute DrawTerrain(...)

但是,我不明白如何获取x和y位置或如何在LINQ语句中调用方法。

另外,如果我可以将此代码放入函数并且能够使用委托或谓词调用它,那将会很棒吗?我不知道委托或谓词是否正确。

    void Draw(Delegate draw, bool[,] map, struct[,] tiles) 
        from x in map where x == true draw(titles[x,y]).invoke;
    }

3 个答案:

答案 0 :(得分:1)

嗯,如果你努力工作,你可以用LINQ来做,但这会很痛苦。听起来你的第一段代码绝对没问题。

有一个通用的版本来采取行动似乎非常合理:

public delegate void Drawer(int x, int y, Tile tile);

public void Draw(Drawer drawer, bool[,] map, Tile[,] tiles) {
    for (int x = 0; x < this.Size.Width; x++) {
        for (int y = 0; y < this.Size.Height; y++) {
            if (this.Map[x, y]) {
                drawer(x, y, tiles[x, y]);
            }
        }
    }
}

如果真的想要LINQ版本,那就是:

var query = from x in Enumerable.Range(0, Size.Width)
            from y in Enumerable.Range(0, Size.Height)
            where Map[x, y]
            select new { x, y };

foreach (var pair in query)
{
    DoWhatever(pair.x, pair.y, tiles[pair.x, pair.y]);
}

答案 1 :(得分:1)

您可以执行以下Linq查询以获取x,y值,然后迭代它们以运行您的方法。

var points = from x in Enumerable.Range(0, this.Size.Width - 1)
             from y in Enumerable.Range(0, this.Size.Width - 1)
             where this.Map[x, y]
             select new { X = x, Y = y };
foreach (var p in points)
    DrawTerrain(this.Tile[p.X, p.Y].Location, Terrain.Water);

答案 2 :(得分:1)

LINQ查询语法并非真正用于处理二维数据结构,但您可以编写一个扩展方法,将2D数组转换为包含原始2D数组中坐标的值序列。数组中的值。您需要一个帮助程序类型来存储数据:

class CoordinateValue<T> {
  public T Value { get; set; }
  public int X { get; set; }
  public int Y { get; set; }
}

然后你可以编写扩展方法(对于任何2D数组),如下所示:

IEnumerable<CoordinateValue<T>> AsEnumerable(this T[,] arr) {
  for (int i = 0; i < arr.GetLength(0); i++)
    for (int j = 0; j < arr.GetLength(0); j++)
      yield new CoordinateValue<T> { Value = arr[i, j]; X = i; Y = j; };
}

现在你终于可以开始使用LINQ了。要获取2D数组中所有元素的坐标,使得元素中存储的值为true,您可以使用以下内容:

var toDraw = from tile in this.Map.AsEnumerable()
             where tile.Value == true
             select tile;

// tile contains the coordinates (X, Y) and the original value (Value)
foreach(var tile in toDraw)
    FillTile(tile.X, tile.Y);

这使您可以在过滤切片时指定一些有趣的条件。例如,如果您只想获得对角元素,可以写:

var toDraw = from tile in this.Map.AsEnumerable()
             where tile.Value == true && tile.X == tile.Y
             select tile;

回答第二个问题 - 如果要将行为封装到方法中,您可能需要使用一些Action<...>委托来表示将传递给方法的绘图函数。这取决于绘图方法的类型签名。