В C# 8.0 была добавлена новая функциональность - индексы и диапазоны, которые упрощают получение из массивов подмассивов. Для этого в C# есть два типа: System.Range и System.Index. Оба типа являются структурами. Тип Range представляет некоторый диапазон значений в некоторой последовательность, а тип Index - индекс в последовательности.
Индекс фактически представляет числовое значение, и при определении индекса мы можем указать это значение:
Index myIndex = 2;
В данном случае индекс представляет третий элемент последовательности (индексация начинается с 0).
С помощью специального оператора ^ можно задать индекс относительно конца последовательности.
Index myIndex = ^2;
Теперь индекс представляет второй элемент с конца последовательности, то есть предпоследний элемент.
Используем индексы для получения элементов массива:
Index myIndex1 = 2; // третий элемент Index myIndex2 = ^2; // предпоследний элемент string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" }; string selected1 = people[myIndex1]; // Sam string selected2 = people[myIndex2]; // Kate Console.WriteLine(selected1); Console.WriteLine(selected2);
Фактически для данной задачи индексы не нужны, и мы можем воспользоваться стандартными возможностями массивов:
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);
То есть в подобных ситуациях плюсом индексов является большая удобочитаемость. Так, people[^2]
более читабельно, чем people[people.Length - 2]
.
Диапазон представляет часть последовательности, которая ограничена двумя индексами. Начальный индекс включается в диапазон, а конечный индекс НЕ входит в диапазон. Для определения диапазона применяется оператор ..:
Range myRange1 = 1..4; // по 1-го индекса включая по 4-й индекс не включая
В данном случае диапазон myRange1 включает элементы с 1 индекса по 4-й индекс (не включая). При этом элемент по 4-му индексу не включается в диапазон. При этом границы диапазона задаются не просто числами, а именно объектами Index. То есть следующие определения диапазонов будут равноценны:
Index start = 1; Index end = 4; Range myRange1 = start..end; Range myRange2 = 1..4;
Практическое применение диапазонов - получим со второго по четвертый элементы массива:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" }; string[] peopleRange = people[1..4]; // получаем 2, 3 и 4-й элементы из массива foreach(var person in peopleRange) { Console.WriteLine(person); }
Результатом операции people[1..4]
является подмассив элементов с 1 по 3 индексы (включая). Консольный вывод:
Bob Sam Kate
Мы можем задать для диапазона только конечный индекс. В этом случае начальным индексом по умолчанию будет 0.
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" }; string[] peopleRange = people[..4]; // Tom, Bob, Sam, Kate
Либо, наоборот, задать только начальный индекс, тогда конечным индексом будет последний индекс последовательности:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" }; string[] peopleRange = people[1..]; // Bob, Sam, Kate, Alice
Используя индексы относительно конца последовательности, можно получать диапазон относительно конца последовательности:
string[] people = { "Tom", "Bob", "Sam", "Kate", "Alice" }; string[] peopleRange1 = people[^2..]; // два последних - Kate, Alice string[] peopleRange2 = people[..^1]; // начиная с предпоследнего - Tom, Bob, Sam, Kate string[] peopleRange3 = people[^3..^1]; // два начиная с предпоследнего - Sam, Kate
Кроме массивов индексы и диапазоны также применяются к объектам Span и 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); }