Indecși și Intervaluri
În C# 8.0 a fost adăugată o nouă funcționalitate - indecși și intervaluri, care simplifică obținerea subarray-urilor din array-uri. Pentru aceasta, în C# există două tipuri: System.Range și System.Index. Ambele tipuri sunt structuri. Tipul Range reprezintă un anumit interval de valori într-o secvență, iar tipul Index - un index în secvență.
Ce este Index?
Indexul reprezintă de fapt o valoare numerică, și la definirea indexului putem specifica această valoare:
Index myIndex = 2;
În acest caz, indexul reprezintă al treilea element al secvenței (indexarea începe de la 0).
Cu ajutorul operatorului special ^ putem seta indexul relativ la sfârșitul secvenței.
Index myIndex = ^2;
Acum indexul reprezintă al doilea element de la sfârșitul secvenței, adică penultimul element.
Utilizăm indecșii pentru a obține elemente dintr-un array:
Index myIndex1 = 2; // al treilea element
Index myIndex2 = ^2; // penultimul element
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string selected1 = people[myIndex1]; // Sam
string selected2 = people[myIndex2]; // Kate
Console.WriteLine(selected1);
Console.WriteLine(selected2);
De fapt, pentru această sarcină, indecșii nu sunt necesari și putem folosi capacitățile standard ale array-urilor:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string selected1 = people[2]; // Sam
string selected2 = people[people.Length - 2]; // Kate
Console.WriteLine(selected1);
Console.WriteLine(selected2);
Deci, în astfel de situații, avantajul indecșilor este o mai bună lizibilitate. Astfel, people[^2] este mai lizibil decât people[people.Length - 2].
Intervaluri
Intervalul reprezintă o parte a secvenței, care este delimitată de doi indecși. Indexul de început este inclus în interval, iar indexul de sfârșit nu este inclus în interval. Pentru a defini un interval se folosește operatorul ..:
Range myRange1 = 1..4; // de la indexul 1 inclusiv până la indexul 4 exclusiv
În acest caz, intervalul myRange1 include elementele de la indexul 1 până la indexul 4 (exclusiv). Indexul de sfârșit nu este inclus în interval. Limitele intervalului sunt specificate nu doar prin numere, ci prin obiecte Index. Deci, următoarele definiții ale intervalurilor vor fi echivalente:
Index start = 1;
Index end = 4;
Range myRange1 = start..end;
Range myRange2 = 1..4;
Utilizarea practică a intervalurilor - obținem al doilea până la al patrulea element dintr-un array:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string[] peopleRange = people[1..4]; // obținem elementele 2, 3 și 4 din array
foreach (var person in peopleRange)
{
Console.WriteLine(person);
}
Rezultatul operației people[1..4] este un subarray de elemente de la indexul 1 la indexul 3 (inclusiv). Ieșirea în consolă:
Bob
Sam
Kate
Putem specifica doar indexul de sfârșit pentru un interval. În acest caz, indexul de început va fi implicit 0.
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string[] peopleRange = people[..4]; // Tom, Bob, Sam, Kate
Sau, dimpotrivă, să specificăm doar indexul de început, atunci indexul de sfârșit va fi ultimul index din secvență:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string[] peopleRange = people[1..]; // Bob, Sam, Kate, Alice
Folosind indecși relativi la sfârșitul secvenței, putem obține un interval relativ la sfârșitul secvenței:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
string[] peopleRange1 = people[^2..]; // ultimele două - Kate, Alice
string[] peopleRange2 = people[..^1]; // de la început până la penultimul - Tom, Bob, Sam, Kate
string[] peopleRange3 = people[^3..^1]; // două începând cu penultimul - Sam, Kate
Pe lângă array-uri, indecșii și intervalurile se aplică și obiectelor Span și ReadOnlySpan:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" };
Span<string> peopleSpan = people;
Span<string> selectedPeopleSpan = peopleSpan[1..4];
foreach (var person in selectedPeopleSpan)
{
Console.WriteLine(person);
}