如何按网格的部分划分二次量?

时间:2016-10-21 23:56:32

标签: c# algorithm linq grid

我遇到以下问题:有一个网格,每个网格单元都有一个位置。这种网格的一个例子可以是以下一个:

_________________________________________
|       |       |       |       |       |
| (0,0) | (1,0) | (2,0) | (3,0) | (4,0) |
|_______|_______|_______|_______|_______|
|       |       |       |       |       |
| (0,1) | (1,1) | (2,1) | (3,1) | (4,1) |
|_______|_______|_______|_______|_______|
|       |       |       |       |       |
| (0,2) | (1,2) | (2,2) | (3,2) | (4,2) |
|_______|_______|_______|_______|_______|
|       |       |       |       |       |
| (0,3) | (1,3) | (2,3) | (3,3) | (4,3) |
|_______|_______|_______|_______|_______|
|       |       |       |       |       |
| (0,4) | (1,4) | (2,4) | (3,4) | (4,4) |
|_______|_______|_______|_______|_______|

我需要创建一个函数,给定一个数字 N ,最多创建该数字的二次 NxN 数量的组。例如,对于N = 2,每组最多包含2x2个单元,第1组将包含[(0,0)(1,0)(0,1)(1,1)],第2组[(2 ,0)(3,0)(2,1)(3,1)],第3组只包含[(4,0)(4,1)]等等。

我使用C#,所以这在概念上是按操作分组,我决定使用LINQ Group By 函数,但是它需要一个必须计算必须的数字的lambda表达式每组都一样。因此,我正在查看一个表达式,对于我的n = 2的问题,必须为[(0,0)(1,0)(0,1)(1,1)]返回相同的数字, [(2,0)(3,0)(2,1)(3,1)]的数字,[(4,0)(4,1)]等的不同...

哪种表达可以实现该属性?

谢谢

1 个答案:

答案 0 :(得分:1)

要使用' Group By' -operation,您需要定义要分组的键。 在这种情况下,如果它是关于网格的,我能想到的唯一可能的关键是基于网格中行/列索引的计算结果。 我觉得解释我在纯文本中选择的计算有点困难,所以我希望下面的例子可以帮我说话。

这回答或帮助解决您的问题吗?

测试数据/设置

var grid = new List<List<string>>();

grid.Add(new List<string>(new[] { "0,0", "1,0", "2,0", "3,0", "4,0" }));
grid.Add(new List<string>(new[] { "0,1", "1,1", "2,1", "3,1", "4,1" }));

grid.Add(new List<string>(new[] { "0,2", "1,2", "2,2", "3,2", "4,2" }));
grid.Add(new List<string>(new[] { "0,3", "1,3", "2,3", "3,3", "4,3" }));

grid.Add(new List<string>(new[] { "0,4", "1,4", "2,4", "3,4", "4,4" }));

// Quadratic group factor.
int n = 2;

解决方案1 ​​ - Lambda表达式

var result_1 = grid

    // Create quadratic groups by calculating the combined index of the row+column with the quadratic group factor.
    .SelectMany(r =>
        r.GroupBy(c =>
            (int)Math.Floor((double)grid.IndexOf(r) / (double)n)
                + "_" +
            (int)Math.Floor((double)r.IndexOf(c) / (double)n)
        )
    )

    // Combine all same keys together in one group.
    .GroupBy(g => g.Key)

    // Get all results per group.
    .Select(gg => gg.SelectMany(g => g).ToList())

    // ToList() because it's easier to inspect the value of the result while debugging.
    .ToList();

// Short version:
var result_2 = grid
    .SelectMany(r =>
        r.GroupBy(c =>
            (int)Math.Floor((double)grid.IndexOf(r) / (double)n) + "_" + (int)Math.Floor((double)r.IndexOf(c) / (double)n)
        )
    )
    .GroupBy(g => g.Key)
    .Select(gg => gg.SelectMany(g => g).ToList())
    .ToList();

解决方案2 - Oldschool循环,可能更容易/更好理解。

var result_3 = new List<List<string>>();

// Range (amount of both 'rows' and 'columns' since it's a grid).
int range = (int)Math.Ceiling((double)grid.Count / (double)n);

// Loop through 'rows'.
for(var y = 0; y < range; y++)
{
    int skipRowsAmount = (y * n);
    int takeRowsAmount = n;

    // Get all 'rows' to split in groups.
    var rows = grid.Skip(skipRowsAmount).Take(takeRowsAmount).ToList();

    // Loop through 'columns'.
    for (var x = 0; x < range; x++)
    {
        int skipColumnsAmount = (x * n);
        int takeColumnsAmount = n;

        // Get all 'columns' from all 'rows' to split in groups.
        var quadraticColumns = rows.SelectMany(l => l.Skip(skipColumnsAmount).Take(takeColumnsAmount)).ToList();

        // Add the quadratic columns group to the result.
        result_3.Add(quadraticColumns);
    }
}

编辑 - 将组密钥从字符串更改为整数的代码

.SelectMany(r =>
    r.GroupBy(c =>
        (((int)Math.Floor((double)grid.IndexOf(r) / (double)n)) * ((int)Math.Ceiling((double)grid.Count / (double)n)))
            +
        (int)Math.Floor((double)r.IndexOf(c) / (double)n)
    )
)