【问题标题】:Get All Diagonals in a 2 Dimensional Matrix Using LINQ使用 LINQ 获取二维矩阵中的所有对角线
【发布时间】:2017-02-11 05:00:09
【问题描述】:

给定下面的二维矩阵

int[][] m = new int[][] {   new int[] { 1, 2, 3, 4 },
                            new int[] { 0, 1, 4, 3 },
                            new int[] { 4, 0, 2, 2 },
                            new int[] { 4, 2, 0, 1 }};

我想使用 LINQ 来获取所有对角线,即

4 3 3 2 4 2 1 1 2 1 0 0 0 4 2 4

现在我正在使用两个丑陋的 for 循环,但我知道必须有更好的方法。

List<List<int>> e = new List<List<int>>();
for (int i = 0; i < m.Count(); i++)
{
    for (int j = m.Count() - 1; j >= 0; j--)
    {
        if (i == 0 || (i > 0 && j == 0))
        {
            e.Add(new List<int> { m[i][j] });
        }

        if (i > 0 && j > 0)
        {
            e[i - j + m.Count() - 1].Add(m[i][j]);
        }
    }
}

【问题讨论】:

    标签: c# arrays linq matrix


    【解决方案1】:

    将矩阵展平,然后按创建的键分组:

    var d = m.SelectMany((row, rowIdx) =>
            row.Select((x, colIdx) => new { Key = rowIdx - colIdx, Value = x }))
        .GroupBy(x => x.Key, (key, values) => values.Select(i => i.Value).ToArray())
        .ToArray();
    

    如果对角线需要按逻辑顺序排列,还需要对结果进行排序:

    var d2 = m.SelectMany((row, rowIdx) => 
             row.Select((x, colIdx) => new { Key = rowIdx - colIdx, Value = x }))
        .GroupBy(x => x.Key)
        .OrderBy(x => x.Key)
        .Select(values => values.Select(i => i.Value).ToArray())
        .ToArray();
    

    【讨论】:

    • 谢谢。两种说法都很安静。抱歉,我的声誉分数低于 15 分,因此无法投票。
    • ToArray() 是一个相当昂贵的调用。虽然这个答案对所提出的问题是有效的......我认为这个问题的 LINQ 要求确实引入了复杂性和性能问题。
    【解决方案2】:

    使用 LINQ

    据我所知,这个特殊的问题并没有真正从使用 LINQ 中获得任何性能优势。也许您可以进一步解释该要求,因为性能损失和增加的复杂性似乎不会产生比您当前或任何其他仅实现问题的迭代方法的解决方案更“优雅”的解决方案。


    替代方案:使用 Math.Abs​​ 方法

    我认为使用Math.Abs() 会给你一个有效的循环

    int length = 4;
    for (int i = -length; i <= Math.Abs(length); i++)
    {
        Console.WriteLine(i);
        // -4, -3, -2, -1,  0, +1, +2, +3, +4
    }
    

    这可能是使用Math.Abs() 的潜在解决方案。当它通过中心对角线时,它会颠倒顺序。

    int[][] m = new int[][] {
        new int[] { 1, 2, 3, 4 },
        new int[] { 0, 1, 4, 3 },
        new int[] { 4, 0, 2, 2 },
        new int[] { 4, 2, 0, 1 }};
    
    int max = m.Length;
    for (int i = -max+1; Math.Abs(i) < max; i++)
    {
        for (int j = 0; j <= max - Math.Abs(i) - 1; j++)
        {
            int row = i < 0 ? j : i + j;
            int col = i > 0 ? j : (Math.Abs(i) + j);
            Console.Write(m[row][col]);
        }
        Console.WriteLine();
    }
    

    【讨论】:

    • 是的,这也很有效,是对我一开始的改进,但我希望完全避免循环并使用 LINQ 来获得更优雅的解决方案。
    • 我已经更新了我的答案,在查看了要求后,我没有看到强制使用 LINQ 语句解决这个问题的意义,因为 LINQ 语句将转换为性能成本和整体膨胀在运行时似乎并没有使解决方案更“优雅”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2023-04-08
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2016-02-15
    相关资源
    最近更新 更多