二维数组切片

2D array slicing

由于现在有可能使用像 arr[1..4] 这样偷偷摸摸的峰值方式对数组进行切片,所以我想对二维数组进行切片。

考虑以下几点:

int[][] matrix = new int[4][]
{
    new int[] {1,2,3,4 },
    new int[] {5,6,7,8 },
    new int[] {9,10,11,12 },
    new int[] {13,14,15,16 }
};

foreach (var item in matrix[0..2][0..2].SelectMany(x => x))
{
    Console.Write(item + " ");
}
// output: 1 2 3 4 5 6 7 8 

foreach (var item in matrix[0..3][0..2].SelectMany(x => x))
{
    Console.Write(item + " ");
}
// output: 1 2 3 4 5 6 7 8


foreach (var item in matrix[0..1][0..2].SelectMany(x => x))
{
    Console.Write(item + " ");
}
// Error : System.ArgumentOutOfRangeException: 'Specified argument was out of the range of valid values

我希望第一个输出为 1 2 5 6,第二个为 1 2 5 6 9 10,第三个为 1 2

如何在 "slicing manner" 中实现预期输出?

P.S。是我还是这是违反直觉的行为。

这个行得通...您需要对第一个切片生成的子集中的每一行进行切片,而不是行集合本身:

matrix[0..3].SelectMany(r => r[0..2])

切片索引作用于一个集合并产生一个新集合,这与标量索引不同,标量索引 returns 是集合的一个元素。因此,索引现在再次作用于切片而不是切片内的元素......所以你需要使用 select 来应用到每个元素。

当你这样做时:

var slice = matrix[0..2][0..2];

您实际上将数组切片两次。相当于写:

var temp = matrix[0..2];
var slice = temp[0..2];

在这种情况下,使第二个切片变得多余。您可以通过以下方式确认:

var slice = matrix[0..2][0..3]

在这种情况下,第二个切片将抛出异常,因为它比第一个切片大。

我认为你想做的是:

foreach (var item in matrix[0..2].SelectMany(x => x[0..2]))
{
}