1: Background
1. Tell a story
Yesterday on GitHub, I was going to find out what new grammars C # 9 has to try. I found a strange way to write it in a documentforeach (var item in myArray[0..5])
Ha ha, familiar and strange, friends who have played Python are interested in this[0..5]
I’m too familiar with it. I even met it in c#. I’m happy. I saw the new grammar of c#8. It’s ironic. I made 9 before I was familiar with 8. I have a strong desire to explore. I always want to see what the bottom of this thing is supported by.
2: The usage of sugar
From the previous introductionmyArray[0..5]
Semantically, we can see that this is an operation to segment array. How many segmentation methods are there? To facilitate the demonstration, I first define an array. The code is as follows:
var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };
1. Extract the first three elements of arr
If you use LINQ, you can use take (3). If you use slicing, it is [0.. 3]. The code is as follows:
static void Main(string[] args)
{
var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };
//1. Get the first three elements of the array
var query1 = myarr[0..3];
var query2 = myarr.Take(3).ToList();
Console.WriteLine($"query1={string.Join(",", query1)}");
Console.WriteLine($"query2={string.Join(",", query2)}");
}
2. Extract the last three elements of arr
How to extract this? In Python, you can use – 3 directly. In C #, you need to use ^, starting from the end. The code is as follows:
static void Main(string[] args)
{
var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };
//1. Get the last three elements of the array
var query1 = myarr[^3..];
var query2 = myarr.Skip(myarr.Length - 3).ToList();
Console.WriteLine($"query1={string.Join(",", query1)}");
Console.WriteLine($"query2={string.Join(",", query2)}");
}
3. Extract the three position elements of index = 4, 5 and 6 in the array
If you use LINQ, you need to use itSkip + Take
Double combination, if you use slicing operation, it’s too simple…
static void Main(string[] args)
{
var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };
//1. Get the elements of index = 4, 5 and 6 in the array
var query1 = myarr[4..7];
var query2 = myarr.Skip(4).Take(3).ToList();
Console.WriteLine($"query1={string.Join(",", query1)}");
Console.WriteLine($"query2={string.Join(",", query2)}");
}
Cut from above[4..7]
According to the output, this is a problemLeft closed right open
So pay special attention.
4. Get the penultimate and second elements in the array
If you understand the previous two usages, I believe you will write them quickly. The code is as follows:
static void Main(string[] args)
{
var myarr = new string[] { "10", "20", "30", "40", "50", "60", "70", "80", "90", "100" };
//1. Get the penultimate and second elements in the array
var query1 = myarr[^3..^1];
var query2 = myarr.Skip(myarr.Length - 3).Take(2).ToList();
Console.WriteLine($"query1={string.Join(",", query1)}");
Console.WriteLine($"query2={string.Join(",", query2)}");
}
3、 Explore the principle
Through the first four examples, I think we all know how to play. The next step is to see what supports are used inside. Here we use dnspy to dig.
1. From myarr [0.. 3]
The code is as follows:
//Before Compilation
var query1 = myarr[0..3];
//After compilation:
string[] query = RuntimeHelpers.GetSubArray<string>(myarr, new Range(0, 3));
From the compiled code, we can see that the original array to get the slice is the callRuntimeHelpers.GetSubArray
Yes, and I’ll simplify the method. The code is as follows:
public static T[] GetSubArray<[Nullable(2)] T>(T[] array, Range range)
{
ValueTuple<int, int> offsetAndLength = range.GetOffsetAndLength(array.Length);
int item = offsetAndLength.Item1;
int item2 = offsetAndLength.Item2;
T[] array3 = new T[item2];
Buffer.Memmove<T>(Unsafe.As<byte, T>(array3.GetRawSzArrayData()), Unsafe.Add<T>(Unsafe.As<byte, T>(array.GetRawSzArrayData()), item), (ulong)item2);
return array3;
}
As you can see from the above code, the last subarray is created byBuffer.Memmove
But the cutting position given to the subarray is determined by theGetOffsetAndLength
Method implementation, continue to follow the code:
public readonly struct Range : IEquatable<Range>
{
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end)
{
this.Start = start;
this.End = end;
}
public ValueTuple<int, int> GetOffsetAndLength(int length)
{
Index start = this.Start;
int num;
if (start.IsFromEnd)
{
num = length - start.Value;
}
else
{
num = start.Value;
}
Index end = this.End;
int num2;
if (end.IsFromEnd)
{
num2 = length - end.Value;
}
else
{
num2 = end.Value;
}
return new ValueTuple<int, int>(num, num2 - num);
}
}
After reading the above code, you may have two doubts:
1) start.IsFromEnd And end.IsFromEnd What do you mean?
In fact, after reading the above code logic, you can see that isfromend indicates whether the starting point starts from the left or from the right, which is so simple.
2) I didn’t see it start.IsFromEnd And end.IsFromEnd How to assign value.
In the constructor of the index class, it depends on how the previous layer inserts true or false in the new index. The code is as follows:
The process of this example is as follows:new Range(1,3) -> operator Index(int value) -> FromStart(value) -> new Index(value)
You can see that the optional parameters are not assigned at the end of new.
2. Explore myarr1
In the example just now, the optional parameter is not assigned. Let’s see if the new index is assigned in this example?
//Before compiling:
var query1 = myarr[^3..];
//After compilation:
string[] query = RuntimeHelpers.GetSubArray<string>(myarr, Range.StartAt(new Index(3, true)));
See, this time in the new index, isfromend = true is given, which means that the calculation starts from the end. Combined with the getoffsetandlength method, I think you should straighten out the logic.
4: Summary
Generally speaking, this slicing operation is too practical. It can greatly reduce the use of skip & take for arr and substring for string"12345"[1..3]
-> "12345".Substring(1, 2)
Hey, hey, that’s great! Or c-dafa??
More high quality dry goods: see my GitHub:dotnetfly
- 3.. ↩