Range in c sharp

Indices and ranges

Ranges and indices provide a succinct syntax for accessing single elements or ranges in a sequence.

In this tutorial, you’ll learn how to:

  • Use the syntax for ranges in a sequence.
  • Implicitly define a Range.
  • Understand the design decisions for the start and end of each sequence.
  • Learn scenarios for the Index and Range types.

Language support for indices and ranges

Indices and ranges provide a succinct syntax for accessing single elements or ranges in a sequence.

This language support relies on two new types and two new operators:

  • System.Index represents an index into a sequence.
  • The index from end operator ^ , which specifies that an index is relative to the end of a sequence.
  • System.Range represents a sub range of a sequence.
  • The range operator .. , which specifies the start and end of a range as its operands.

Let’s start with the rules for indices. Consider an array sequence . The 0 index is the same as sequence[0] . The ^0 index is the same as sequence[sequence.Length] . The expression sequence[^0] does throw an exception, just as sequence[sequence.Length] does. For any number n , the index ^n is the same as sequence.Length — n .

string[] words = new string[] < // index from start index from end "The", // 0 ^9 "quick", // 1 ^8 "brown", // 2 ^7 "fox", // 3 ^6 "jumps", // 4 ^5 "over", // 5 ^4 "the", // 6 ^3 "lazy", // 7 ^2 "dog" // 8 ^1 >; // 9 (or words.Length) ^0 

You can retrieve the last word with the ^1 index. Add the following code below the initialization:

Console.WriteLine($"The last word is "); 

A range specifies the start and end of a range. The start of the range is inclusive, but the end of the range is exclusive, meaning the start is included in the range but the end isn’t included in the range. The range [0..^0] represents the entire range, just as [0..sequence.Length] represents the entire range.

The following code creates a subrange with the words «quick», «brown», and «fox». It includes words[1] through words[3] . The element words[4] isn’t in the range.

string[] quickBrownFox = words[1..4]; foreach (var word in quickBrownFox) Console.Write($" < >"); Console.WriteLine(); 

The following code returns the range with «lazy» and «dog». It includes words[^2] and words[^1] . The end index words[^0] isn’t included. Add the following code as well:

string[] lazyDog = words[^2..^0]; foreach (var word in lazyDog) Console.Write($" < >"); Console.WriteLine(); 

The following examples create ranges that are open ended for the start, end, or both:

string[] allWords = words[..]; // contains "The" through "dog". string[] firstPhrase = words[..4]; // contains "The" through "fox" string[] lastPhrase = words[6..]; // contains "the", "lazy" and "dog" foreach (var word in allWords) Console.Write($" < >"); Console.WriteLine(); foreach (var word in firstPhrase) Console.Write($" < >"); Console.WriteLine(); foreach (var word in lastPhrase) Console.Write($" < >"); Console.WriteLine(); 

You can also declare ranges or indices as variables. The variable can then be used inside the [ and ] characters:

Index the = ^3; Console.WriteLine(words[the]); Range phrase = 1..4; string[] text = words[phrase]; foreach (var word in text) Console.Write($" < >"); Console.WriteLine(); 

The following sample shows many of the reasons for those choices. Modify x , y , and z to try different combinations. When you experiment, use values where x is less than y , and y is less than z for valid combinations. Add the following code in a new method. Try different combinations:

int[] numbers = Enumerable.Range(0, 100).ToArray(); int x = 12; int y = 25; int z = 36; Console.WriteLine($" is the same as "); Console.WriteLine($" is the same as "); Console.WriteLine("numbers[x..y] and numbers[y..z] are consecutive and disjoint:"); Span x_y = numbers[x..y]; Span y_z = numbers[y..z]; Console.WriteLine($"\tnumbers[x..y] is through , numbers[y..z] is through "); Console.WriteLine("numbers[x..^x] removes x elements at each end:"); Span x_x = numbers[x..^x]; Console.WriteLine($"\tnumbers[x..^x] starts with and ends with "); Console.WriteLine("numbers[..x] means numbers[0..x] and numbers[x..] means numbers[x..^0]"); Span start_x = numbers[..x]; Span zero_x = numbers[0..x]; Console.WriteLine($"\t.. is the same as .."); Span z_end = numbers[z..]; Span z_zero = numbers[z..^0]; Console.WriteLine($"\t.. is the same as .."); 

Not only arrays support indices and ranges. You can also use indices and ranges with string, Span , or ReadOnlySpan .

Implicit range operator expression conversions

When using the range operator expression syntax, the compiler implicitly converts the start and end values to an Index and from them, creates a new Range instance. The following code shows an example implicit conversion from the range operator expression syntax, and its corresponding explicit alternative:

Range implicitRange = 3..^5; Range explicitRange = new( start: new Index(value: 3, fromEnd: false), end: new Index(value: 5, fromEnd: true)); if (implicitRange.Equals(explicitRange)) < Console.WriteLine( $"The implicit range '' equals the explicit range ''"); > // Sample output: // The implicit range '3..^5' equals the explicit range '3..^5' 

Implicit conversions from Int32 to Index throw an ArgumentOutOfRangeException when the value is negative. Likewise, the Index constructor throws an ArgumentOutOfRangeException when the value parameter is negative.

Type support for indices and ranges

Indexes and ranges provide clear, concise syntax to access a single element or a range of elements in a sequence. An index expression typically returns the type of the elements of a sequence. A range expression typically returns the same sequence type as the source sequence.

Any type that provides an indexer with an Index or Range parameter explicitly supports indices or ranges respectively. An indexer that takes a single Range parameter may return a different sequence type, such as System.Span .

The performance of code using the range operator depends on the type of the sequence operand.

The time complexity of the range operator depends on the sequence type. For example, if the sequence is a string or an array, then the result is a copy of the specified section of the input, so the time complexity is O(N) (where N is the length of the range). On the other hand, if it’s a System.Span or a System.Memory , the result references the same backing store, which means there is no copy and the operation is O(1).

In addition to the time complexity, this causes extra allocations and copies, impacting performance. In performance sensitive code, consider using Span or Memory as the sequence type, since the range operator does not allocate for them.

A type is countable if it has a property named Length or Count with an accessible getter and a return type of int . A countable type that doesn’t explicitly support indices or ranges may provide an implicit support for them. For more information, see the Implicit Index support and Implicit Range support sections of the feature proposal note. Ranges using implicit range support return the same sequence type as the source sequence.

Array has more nuanced behavior. Single dimension arrays support both indices and ranges. Multi-dimensional arrays don’t support indexers or ranges. The indexer for a multi-dimensional array has multiple parameters, not a single parameter. Jagged arrays, also referred to as an array of arrays, support both ranges and indexers. The following example shows how to iterate a rectangular subsection of a jagged array. It iterates the section in the center, excluding the first and last three rows, and the first and last two columns from each selected row:

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.Write($", "); > Console.WriteLine(); > 

In all cases, the range operator for Array allocates an array to store the elements returned.

Scenarios for indices and ranges

You’ll often use ranges and indices when you want to analyze a portion of a larger sequence. The new syntax is clearer in reading exactly what portion of the sequence is involved. The local function MovingAverage takes a Range as its argument. The method then enumerates just that range when calculating the min, max, and average. Try the following code in your project:

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 to : \tMin: ,\tMax: ,\tAverage: "); > for (int start = 0; start < sequence.Length; start += 100) < Range r = ^(start + 10)..^start; var (min, max, average) = MovingAverage(sequence, r); Console.WriteLine($"From to : \tMin: ,\tMax: ,\tAverage: "); > (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(); 

A Note on Range Indices and Arrays

When taking a range from an array, the result is an array that is copied from the initial array, rather than referenced. Modifying values in the resulting array will not change values in the initial array.

var arrayOfFiveItems = new[] < 1, 2, 3, 4, 5 >; var firstThreeItems = arrayOfFiveItems[..3]; // contains 1,2,3 firstThreeItems[0] = 11; // now contains 11,2,3 Console.WriteLine(string.Join(",", firstThreeItems)); Console.WriteLine(string.Join(",", arrayOfFiveItems)); // output: // 11,2,3 // 1,2,3,4,5 

Feedback

Submit and view feedback for

Источник

Range in c sharp

В C# 8.0 была добавлена новая функциональность — индексы и диапазоны, которые упрощают получение из массивов подмассивов. Для этого в C# есть два типа: System.Range и System.Index . Оба типа являются структурами. Тип Range представляет некоторый диапазон значений в некоторой последовательность, а тип Index — индекс в последовательности.

Индексы

Индекс фактически представляет числовое значение, и при определении индекса мы можем указать это значение:

В данном случае индекс представляет третий элемент последовательности (индексация начинается с 0).

С помощью специального оператора ^ можно задать индекс относительно конца последовательности.

Теперь индекс представляет второй элемент с конца последовательности, то есть предпоследний элемент.

Используем индексы для получения элементов массива:

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)

Результатом операции people[1..4] является подмассив элементов с 1 по 3 индексы (включая). Консольный вывод:

Мы можем задать для диапазона только конечный индекс. В этом случае начальным индексом по умолчанию будет 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 peopleSpan = people; Span selectedPeopleSpan = peopleSpan[1..4]; foreach (var person in selectedPeopleSpan)

Источник

Читайте также:  How to run python script in terminal
Оцените статью