24
C# Ranges and Indexes
In this tutorial, we're going to go through two new .NET types - System.Index
, System.Range
and cover appropriate operators: ^
and ..
.
If you are interested in learning more about C# language, this is for you.
You’ll be able to use the skills and lessons in this tutorial in the real dev world when you work on any project using C#.
It will provide you with a more elegant way to work with sequences and laconic syntax to access elements. Long story short - to use modern language constructions to write easily readable and understandable code.
Ranges and Indexes were introduced as part of .NET Standard 2.1. This is C# 8 feature. It is available in .NET 5, netcore 3.0. It is not supported by .NET Framework. It can be applied for arrays, spans, and readonly spans.
First, go to your favorite IDE, it might be Visual Studio, VS Code, Rider, LINQPad, etc. Make sure to start with nothing open or running (except your computer!) I prefer Visual Studio
Next, create a new project and go through the steps.
The dataset I’m going to use for this tutorial is just a string array of languages.
Create a collection. Let's create an array with the languages.
var languages = new string[] { "Spanish", "English", "Japanese", "French", "German", "Russian", "Italian", "Korean", "Chinese" };
How can we get the second element - "English"? It is pretty easy to do, we just have to pass the index (remember that the numeration if indexes in collections in C# starts from 0)
int index = 1;
var english = languages[index];
Console.WriteLine(english); // Output: English
Instead of int
variable we can use Index
type for doing the same:
Index index1 = 1;
var english2 = languages[index1];
Console.WriteLine(english2);
Here is another way to create index. Index
is value type so when we do new Index()
it will set the default value to 0
var index2 = new Index(); // zero by default because this is a structure
var spanish = languages[index2];
Console.WriteLine(spanish);
We can pass the index value as a parameter to the constructor
var index3 = new Index(2);
var japanese = languages[index3];
Console.WriteLine(japanese);
Probably for now you might ask what is the benefit to use index rather than just integer variable? Okay, probably for accessing the first or second elements there are no many benefits. But in the next examples, we will see getting the last element and will see much more benefits when we will try indexes with ranges together.
The second question here is how can we get the last element? Okay, we can simply get the length of the array and subtract 1
. (because of the first element has the index 0
that's way the last element has the index last element - 1
)
var lastIndex1 = languages.Length - 1;
var chinese1 = languages[lastIndex1];
Console.WriteLine(chinese1);
And the same by using Index:
Index lastIndex2 = ^1;
var chinese2 = languages[lastIndex2];
Console.WriteLine(chinese2);
We can do both above examples in one line.
Console.WriteLine(languages[languages.Length - 2]); // Korean
vs
Console.WriteLine(languages[^2]); // Korean
The struct Index
has overwritten method Equals
so we can check the equality of the two indexes.
var equals = index1.Equals(index2);
Console.WriteLine(equals); // false
Usually, users are forced to implement complex structures to filter/operate on slices of memory or resort to LINQ methods like list.Skip(5).Take(2)
. With the addition of System.Span<T>
and other similar types, it becomes more important to have this kind of operation supported on a deeper level in the language/runtime and have the interface unified.
Range operator ..
is a binary infix operator that accepts two expressions, or both expressions can be omitted.
Range myRange1 = 1..4;
This can be used with indexes together:
Index start = 1;
Index end = 4;
Range myRange2 = start..end;
The following will output the 1
, 2
and 3
elements from array:
string[] languagesRange = languages[1..4];
foreach (var language in languagesRange)
{
Console.WriteLine(language);
}
A bit more interesting usages.
3 last elements:
string[] languagesRange1 = languages[^3..];
From start to pre-last element (every except the last one)
string[] languagesRange2 = languages[..^1];
3 elements before pre-last element
string[] languagesRange3 = languages[^4..^1];
As I mentioned earlier the same we can do with Span
Span<string> languagesSpan = languages;
Span<string> selectedLanguagesSpan = languagesSpan[1..4];
foreach (var language in selectedLanguagesSpan)
{
Console.WriteLine(language);
}
Thank you very much for reading. I hope it brought something new to you. Hope you'll find a chance to give it a try for these features in your projects. Also, I would appreciate any feedback from you. Feel free to post your comments below.
The source code can be found here.
24