- Span
C# 7 里面出现了Span这个数据类型,它可以表示另一个数据结构里连续相邻的一串数据,并且它是内存安全的
static void TestSpan()
{
//var arr = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var arr = Enumerable.Range(1, 10).ToArray();
Span<int> slice = arr.AsSpan().Slice(2, 4);
Console.WriteLine(string.Join(",", slice.ToArray()));
}
//返回3,4,5,6
```c#
- Range
而C# 8里面我们可以从一个序列里面很简单的提取出来一个子范围组成新的序列。
```c#
int[] someArray = Enumerable.Range(1, 5).ToArray();
int[] subArray1 = someArray[0..2];//{1,2}
Console.WriteLine(string.Join(",", subArray1));
//返回1,2
这里面使用了范围运算符..
。
arr[2..4]
表示把arr这个序列,从索引为2的元素一直到索引为4(但不包括索引4)的元素提取出来组成新的序列。所以结果就是3,4
更多Range例子:
//int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
int[] someArray = Enumerable.Range(1, 5).ToArray();
int[] subArray1 = someArray[0..2];//{1,2}
Console.WriteLine(string.Join(",", subArray1));
int[] subArray2 = someArray[1..^0];//{2,3,4,5}
Console.WriteLine(string.Join(",", subArray2));
int[] subArray3 = someArray[1..];
Console.WriteLine(string.Join(",", subArray3));
List<int> otherArray = new List<int> { 1, 2, 3, 4, 5 };
int[] other1 = otherArray.ToArray()[1..2];
//创建Range对象
//var arr = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var arr = Enumerable.Range(1, 10).ToArray();
Index middle = 4;
Index threeFromEnd = ^3;//Hat运算符^
Range range = middle..threeFromEnd;
int[] slice = arr[range];
Console.WriteLine(string.Join(",", slice));
//使用Index类型和^操作符
Index index = ^2;
var number = arr[index];
Console.WriteLine(number);//9
//使用Range和Index
var arrTwin = arr[0..^0];//arrTwin是arr的完成拷贝
foreach (var i in arrTwin)
{
Console.WriteLine(i);
}
var arrTwin2 = arr[..];//arr[0..^0];的简化版, 还等同于 arr[0..10];
foreach (var i in arrTwin2)
{
Console.WriteLine(i);
}
int[] arrTwin3 = arr[..];//完成的复制,数组
int[] allButFirst = arr[1..];//不包含第一个元素的数组
int[] empty = arr[^0..];//空数组
int[] onlyLastItem = arr[^1..];//只包含最后一个元素的数组
int[] last4Items = arr[^4..];//包含四个元素的数组
int lastItem = arr[^1];//最后一个元素,类型是int
- Range操作二维数组
循环访问位于中心的节,不包括前三行和后三行,以及每个选定行中的前两列和后两列:
static void TestRange2()
{
var jagged = new int[10][]{
new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
new int[10] { 10,11,12,13,14,15,16,17,18,19},
new int[10] { 20,21,22,23,24,25,26,27,28,29},
new int[10] { 30,31,32,33,34,35,36,37,38,39},
new int[10] { 40,41,42,43,44,45,46,47,48,49},
new int[10] { 50,51,52,53,54,55,56,57,58,59},
new int[10] { 60,61,62,63,64,65,66,67,68,69},
new int[10] { 70,71,72,73,74,75,76,77,78,79},
new int[10] { 80,81,82,83,84,85,86,87,88,89},
new int[10] { 90,91,92,93,94,95,96,97,98,99},
};
var selectedRows = jagged[3..^3];
foreach (var row in selectedRows)
{
var selectedColumns = row[2..^2];
foreach (var cell in selectedColumns)
{
Console.WriteLine($"{cell}, ");
}
Console.WriteLine();
}
}
- Range的应用场景
要分析较大序列的子范围时,通常会使用范围和索引。 在准确读取所涉及的子范围这一方面,新语法更清晰。 本地函数MovingAverage
以 Range 为参数。 然后,该方法在计算最小值、最大值和平均值时仅枚举该范围。
static void TestRange3()
{
//同时返回多个值
(int min, int max, double average) MovingAverage(int[] subSequence, Range range) => (
subSequence[range].Min(),
subSequence[range].Max(),
subSequence[range].Average()
);
int[] Sequence(int count) => Enumerable.Range(0, count).Select(x => (int)(Math.Sqrt(x) * 100)).ToArray();
int[] sequence = Sequence(1000);
for (int start = 0; start < sequence.Length; start += 100)
{
Range r = start..(start + 10);
var (min, max, average) = MovingAverage(sequence, r);
Console.WriteLine($"From {r.Start} to {r.End}: \tMin: {min},\t{max},\tAverage: {average}");
}
for (int start = 0; start < sequence.Length; start += 100)
{
Range r = ^(start + 10)..^start;
var (min, max, average) = MovingAverage(sequence, r);
Console.WriteLine($"From {r.Start} to {r.End}: \tMin: {min},\tMax: {max},\tAverage: {average}");
}
}
总结:
- Range类型;
一定要注意Range的范围包括Start不包括End。
Range运算符:..
Range应用场景:分析较大序列的子范围时,通常会使用范围和索引,语法更清晰 - Index类型;
从头开始的索引是从0开始的
从尾部开始的索引是从1开始的,与序列的长度相关。 - Hat 运算符:
^
网友评论