Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用LINQ将2D网格转换为“菱形”-可能吗?_C#_Linq - Fatal编程技术网

C# 使用LINQ将2D网格转换为“菱形”-可能吗?

C# 使用LINQ将2D网格转换为“菱形”-可能吗?,c#,linq,C#,Linq,前几天,我需要一种算法,通过有效旋转45度,将2D网格转化为菱形,这样我就可以将对角线序列处理为平面枚举,如下所示: 1 2 3 1 4 5 6 => 4 2 7 8 9 7 5 3 8 6 9 我的算法如下: public static IEnumerable<IEnumerable<T>

前几天,我需要一种算法,通过有效旋转45度,将2D网格转化为菱形,这样我就可以将对角线序列处理为平面枚举,如下所示:

    1 2 3        1         
    4 5 6  =>   4 2      
    7 8 9      7 5 3   
                8 6     
                 9         
我的算法如下:

public static IEnumerable<IEnumerable<T>> RotateGrid<T>(IEnumerable<IEnumerable<T>> grid)
    {
        int bound = grid.Count() - 1;
        int upperLimit = 0;
        int lowerLimit = 0;

        Collection<Collection<T>> rotated = new Collection<Collection<T>>();

        for (int i = 0; i <= (bound * 2); i++)
        {
            Collection<T> row = new Collection<T>();

            for (int j = upperLimit, k = lowerLimit; j >= lowerLimit || k <= upperLimit; j--, k++)
            {
                row.Add(grid.ElementAt(j).ElementAt(k));
            }

            rotated.Add(row);

            if (upperLimit == bound)
                lowerLimit++;

            if (upperLimit < bound)
                upperLimit++;
        }

        return rotated;
    }
能否使用LINQ以更简洁的格式实现这一点


。。或者只是更简洁的格式

以下是我的想法:

void Main()
{
    var lists = new string[] { "123", "456", "789" };

    foreach (var seq in RotateGrid(lists))
        Console.WriteLine(string.Join(", ", seq));
}

public IEnumerable<IEnumerable<T>> RotateGrid<T>(IEnumerable<IEnumerable<T>> grid) 
{
    int rows = grid.Count();
    int cols = grid.First().Count();
    return 
        from i in Enumerable.Range(0, rows + cols - 1)
        select (
            from j in Enumerable.Range(0, i + 1)
            where i - j < rows && j < cols
            select grid.ElementAt(i - j).ElementAt(j)
        );
}
如果您可以假设ILists而不仅仅是IEnumerable,那么这会变得更干净、更高效。我正在考虑一种更有效的方法,不使用.ElementAt,它也可以与IEnumerable一起使用,如果我能写的话,我会发布它

更新:

这是我的更实用的版本,它仍然能够在相当多的linq中使用鞋喇叭。这是一个相当有效的算法,因为它只为每个IEnumerable创建一个枚举数


你不能得到标准2D数组的输入吗?输出是否需要延迟?我不认为使用LINQ是个好主意。另外,矩形输入数组在outpu中会是什么样子?我很想看看其他实现相同功能的实现,但具体来说,我想看看LINQ实现-我知道你可以用LINQ执行几乎任何你喜欢的转换,但我无法在这里实现,部分原因是我在网格上工作时需要“增长和收缩”菱形。我认为通过一些数学的参与,LINQ是可能的。我认为枚举器的构建方式并不是使用LINQ的最佳选择。我认为最好使用一个通用的矩形数组作为输入,然后输出一个通用的锯齿数组。你当然可以把它作为一种扩展方法,但我怀疑枚举数是最好的选择。我同意。特别是对于强制,输入必须是矩形/正方形。我无法想象用锯齿阵列来做这件事。这正是我所想的。但它更多地使用了聪明的数学,而不是LINQ本身。我仍然不认为这可以称为LINQ。但不管怎样,你得到了你的答案。@Euphoric:我正在研究一个更实用的版本,里面有一个循环。也许你会满意的。我永远不会在实践中使用它,因为它的效率非常低。@Euphorit这可能被认为是linq,因为它使用的是枚举数,但我同意它不是linq,因为linq的美妙之处在于它不必知道一切才能工作。这个版本不会很快,我也在尝试一些东西,但它也需要缓存。。。我想知道是否可以通过编写自己的枚举器而不缓存。。。我的意思是这应该是可能的。。。好吧,至少如果你一开始就知道长度,而不必计算。@Recursive Dude你是我的英雄,不是我需要它,而是最终有人了解保持枚举数快速的美妙之处:,并且意识到它们相当于一个国家级,然后只返回一点点收益+1不过,对于较大的集合,最好使用比列表更快的集合,在本例中可能使用字典作为字典,以便进行O1查找。根据这篇文章,如果有超过4个元素,使用字典查找会更快。
1
4, 2
7, 5, 3
8, 6
9
public IEnumerable<IEnumerable<T>> RotateGrid<T>(IEnumerable<IEnumerable<T>> grid) 
{
    var enumerators = new LinkedList<IEnumerator<T>>();
    var diagonal = 
        from e in enumerators
        where e.MoveNext()
        select e.Current;
    foreach (var row in grid)
    {
        enumerators.AddFirst(row.GetEnumerator());
        yield return diagonal.ToArray();
    }

    T[] output;
    while (true)
    {
        output = diagonal.ToArray();
        if(output.Length == 0) yield break;
        yield return output;
    }
}