C# 将二维数组上的两个循环转换为Linq语法

C# 将二维数组上的两个循环转换为Linq语法,c#,arrays,linq,C#,Arrays,Linq,我有一个包含MyObj类型对象的二维数组 我想在传入匹配对象时从数组中获取索引。我想从这个数组中得到x和y值。我可以将这两个值作为采用x和y坐标的位置对象返回 private Position GetIndices(MyObj obj) { for (int x = 0; x < myObjs.GetLength(0); x++) { for (int y = 0; y < myObjs.GetLength(1); y++) {

我有一个包含MyObj类型对象的二维数组

我想在传入匹配对象时从数组中获取索引。我想从这个数组中得到x和y值。我可以将这两个值作为采用x和y坐标的位置对象返回

private Position GetIndices(MyObj obj)
{
    for (int x = 0; x < myObjs.GetLength(0); x++)
    {
        for (int y = 0; y < myObjs.GetLength(1); y++)
        {
            if (myObjs[x, y] == obj)
            {
                return new Position(x, y);
            }
        }
    }
}

是否有可能将此代码缩短为一些Linq代码行?

但我不认为,它看起来很好:

        var result = Enumerable.Range(0, myObjs.GetLength(0))
            .Select(x => Enumerable.Range(0, myObjs.GetLength(1)).Select(y => new { x, y }))
            .SelectMany(o => o)
            .FirstOrDefault(o => myObjs[o.x, o.y] == obj);

但我不认为,它看起来很好:

        var result = Enumerable.Range(0, myObjs.GetLength(0))
            .Select(x => Enumerable.Range(0, myObjs.GetLength(1)).Select(y => new { x, y }))
            .SelectMany(o => o)
            .FirstOrDefault(o => myObjs[o.x, o.y] == obj);

如果你有兴趣,这里还有一个选择。它在第一个select中使用了一个索引器,并进行了一些计算,以找到该索引在二维数组中的位置

var o = new MyObj();

myObjs[1,2] = o;

var p = myObjs.Cast<MyObj>()
              .Select((x,i) => Tuple.Create(x,i))
              .Where(x => x.Item1 == o)
              .Select(x => new Point(x.Item2 / myObjs.GetLength(1), x.Item2 % myObjs.GetLength(1)))
              .SingleOrDefault();

Console.WriteLine(p);  // prints {X=1,Y=2}
看起来你认为x坐标是数组的高度,y坐标是数组的宽度,在这种情况下,你需要稍微调高它:

var p = myObjs.Cast<MyObj>()
              .Select((x,i) => Tuple.Create(x,i))
              .Where(x => x.Item1 == o)
              .Select(x => new Point(x.Item2 % myObjs.GetLength(1), x.Item2 / myObjs.GetLength(1)))
              .SingleOrDefault();

Console.WriteLine(p);  // prints {X=2,Y=1}

我使用Point而不是Position,因为它内置在.NET中,但您应该能够将一个替换为另一个。

如果您感兴趣,这里还有另一个选项。它在第一个select中使用了一个索引器,并进行了一些计算,以找到该索引在二维数组中的位置

var o = new MyObj();

myObjs[1,2] = o;

var p = myObjs.Cast<MyObj>()
              .Select((x,i) => Tuple.Create(x,i))
              .Where(x => x.Item1 == o)
              .Select(x => new Point(x.Item2 / myObjs.GetLength(1), x.Item2 % myObjs.GetLength(1)))
              .SingleOrDefault();

Console.WriteLine(p);  // prints {X=1,Y=2}
看起来你认为x坐标是数组的高度,y坐标是数组的宽度,在这种情况下,你需要稍微调高它:

var p = myObjs.Cast<MyObj>()
              .Select((x,i) => Tuple.Create(x,i))
              .Where(x => x.Item1 == o)
              .Select(x => new Point(x.Item2 % myObjs.GetLength(1), x.Item2 / myObjs.GetLength(1)))
              .SingleOrDefault();

Console.WriteLine(p);  // prints {X=2,Y=1}

我使用Point而不是Position,因为它内置于.NET中,但您应该能够将一个点替换为另一个点。

是的,这是可能的。您可以让Resharper为您执行到linq的作业循环。安装后,.

是的,这是可能的。您可以让Resharper为您执行到linq的作业循环。安装后,.

是的,不太好,从长远来看,传统的For/Foreach更具可读性。Linq被它的语法糖弄坏了:是的,不好,从长远来看,传统的For/Foreach更具可读性。Linq被它的语法糖弄得一团糟:这不是答案,只是建议使用一个工具将代码转换成Linq。问题是如果可能的话。答案是肯定的。这就是答案。还有一个解释是如何做到这一点:询问Resharper。没有人问代码应该是什么样子。这不是答案,只是建议使用一个工具将代码转换为LINQ。问题是如果可能的话。答案是肯定的。这就是答案。还有一个解释是如何做到这一点:询问Resharper。没有人问代码应该是什么样子。