Index et plagesIndices and ranges

Les plages et les index fournissent une syntaxe concise pour accéder à des éléments ou des plages uniques dans une séquence.Ranges and indices provide a succinct syntax for accessing single elements or ranges in a sequence.

Dans ce tutoriel, vous allez apprendre à :In this tutorial, you'll learn how to:

  • Utiliser la syntaxe pour les plages dans une séquence.Use the syntax for ranges in a sequence.
  • Comprendre les décisions de conception pour le début et la fin de chaque séquence.Understand the design decisions for the start and end of each sequence.
  • Découvrir des scénarios pour les types Index et Range.Learn scenarios for the Index and Range types.

Prise en charge linguistique pour les index et les plagesLanguage support for indices and ranges

Cette prise en charge de langage s’appuie sur deux nouveaux types et deux nouveaux opérateurs :This language support relies on two new types and two new operators:

  • System.Index représente un index au sein d’une séquence.System.Index represents an index into a sequence.
  • L’index de l’opérateur end ^, qui spécifie qu’un index est relatif à la fin d’une séquence.The index from end operator ^, which specifies that an index is relative to the end of a sequence.
  • System.Range représente une sous-plage d’une séquence.System.Range represents a sub range of a sequence.
  • L’opérateur de plage .., qui spécifie le début et la fin d’une plage comme opérandes.The range operator .., which specifies the start and end of a range as its operands.

Commençons par les règles concernant les indices.Let's start with the rules for indices. Prenons pour exemple un tableau sequence.Consider an array sequence. L’index 0 est identique à l’index sequence[0].The 0 index is the same as sequence[0]. L’index ^0 est identique à l’index sequence[sequence.Length].The ^0 index is the same as sequence[sequence.Length]. Notez que sequence[^0] lève une exception, tout comme sequence[sequence.Length].Note that sequence[^0] does throw an exception, just as sequence[sequence.Length] does. Pour n’importe quel nombre n, l’index ^n est identique à l’index sequence[sequence.Length - n].For any number n, the index ^n is the same as sequence[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
    "jumped",   // 4                   ^5
    "over",     // 5                   ^4
    "the",      // 6                   ^3
    "lazy",     // 7                   ^2
    "dog"       // 8                   ^1
};              // 9 (or words.Length) ^0

Vous pouvez récupérer le dernier mot avec l’index ^1.You can retrieve the last word with the ^1 index. Ajoutez le code suivant sous l’initialisation :Add the following code below the initialization:

Console.WriteLine($"The last word is {words[^1]}");

Une plage spécifie son début et sa fin.A range specifies the start and end of a range. Les plages sont exclusives, ce qui signifie que la fin n’est pas incluse dans la plage.Ranges are exclusive, meaning the end is not included in the range. La plage [0..^0] représente la plage dans son intégralité, tout comme [0..sequence.Length] représente la plage entière.The range [0..^0] represents the entire range, just as [0..sequence.Length] represents the entire range.

Le code suivant crée une sous-plage qui comporte les mots « quick », « brown » et « fox »The following code creates a subrange with the words "quick", "brown", and "fox". et va de words[1] à words[3].It includes words[1] through words[3]. L’élément words[4] n’est pas dans la plage.The element words[4] isn't in the range. Ajoutez le code suivant à la même méthode.Add the following code to the same method. Copiez-le et collez-le en bas de la fenêtre interactive.Copy and paste it at the bottom of the interactive window.

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

Le code suivant crée une sous-plage qui comporte « lazy » et « dog »The following code creates a subrange with "lazy" and "dog". et comprend words[^2] et words[^1].It includes words[^2] and words[^1]. L’index de fin words[^0] n’est pas inclus.The end index words[^0] isn't included. Ajoutez également le code suivant :Add the following code as well:

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

Les exemples suivants créent des plages ouvertes au début, à la fin ou les deux :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($"< {word} >");
Console.WriteLine();
foreach (var word in firstPhrase)
    Console.Write($"< {word} >");
Console.WriteLine();
foreach (var word in lastPhrase)
    Console.Write($"< {word} >");
Console.WriteLine();

Vous pouvez également déclarer des plages ou index comme variables.You can also declare ranges or indices as variables. La variable peut ensuite être utilisée à l’intérieur des caractères [ et ] :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($"< {word} >");
Console.WriteLine();

L’exemple suivant montre un grand nombre des raisons de ces choix.The following sample shows many of the reasons for those choices. Modifiez x, y et z pour essayer différentes combinaisons.Modify x, y, and z to try different combinations. Quand vous effectuez des essais, utilisez des valeurs de telle sorte que x soit inférieur à y et y inférieur à z pour avoir des combinaisons valides.When you experiment, use values where x is less than y, and y is less than z for valid combinations. Ajoutez le code suivant à une nouvelle méthode.Add the following code in a new method. Essayez différentes combinaisons :Try different combinations:

int[] numbers = Enumerable.Range(0, 100).ToArray();
int x = 12;
int y = 25;
int z = 36;

Console.WriteLine($"{numbers[^x]} is the same as {numbers[numbers.Length - x]}");
Console.WriteLine($"{numbers[x..y].Length} is the same as {y - x}");

Console.WriteLine("numbers[x..y] and numbers[y..z] are consecutive and disjoint:");
Span<int> x_y = numbers[x..y];
Span<int> y_z = numbers[y..z];
Console.WriteLine($"\tnumbers[x..y] is {x_y[0]} through {x_y[^1]}, numbers[y..z] is {y_z[0]} through {y_z[^1]}");

Console.WriteLine("numbers[x..^x] removes x elements at each end:");
Span<int> x_x = numbers[x..^x];
Console.WriteLine($"\tnumbers[x..^x] starts with {x_x[0]} and ends with {x_x[^1]}");

Console.WriteLine("numbers[..x] means numbers[0..x] and numbers[x..] means numbers[x..^0]");
Span<int> start_x = numbers[..x];
Span<int> zero_x = numbers[0..x];
Console.WriteLine($"\t{start_x[0]}..{start_x[^1]} is the same as {zero_x[0]}..{zero_x[^1]}");
Span<int> z_end = numbers[z..];
Span<int> z_zero = numbers[z..^0];
Console.WriteLine($"\t{z_end[0]}..{z_end[^1]} is the same as {z_zero[0]}..{z_zero[^1]}");

Prise en charge des types d’index et de plagesType support for indices and ranges

Les index et les plages fournissent une syntaxe claire et concise permettant d’accéder à un élément unique ou à une sous-plage d’éléments dans une séquence.Indexes and ranges provide clear, concise syntax to access a single element or a sub-range of elements in a sequence. Une expression d’index retourne généralement le type des éléments d’une séquence.An index expression typically returns the type of the elements of a sequence. Une expression de plage retourne généralement le même type de séquence que la séquence source.A range expression typically returns the same sequence type as the source sequence.

Si un type fournit un indexeur avec un paramètre Index ou Range, il prend explicitement en charge les index ou les plages, respectivement.If a type provides an indexer with an Index or Range parameter, it explicitly supports indices or ranges respectively. Lorsque le type fournit un indexeur qui accepte un seul paramètre Range, il peut choisir de retourner un autre type de séquence, tel que System.Span<T>.When the type provides an indexer that takes a single Range parameter, it may choose to return a different sequence type, such as System.Span<T>.

Un type est compté s’il a une propriété nommée Length ou Count avec un accesseur Get accessible et un type de retour int.A type is countable if it has a property named Length or Count with an accessible getter and a return type of int. Un type pouvant être compté qui ne prend pas explicitement en charge les index ou les plages peut fournir une prise en charge implicite pour eux.A countable type that doesn't explicitly support indices or ranges may provide an implicit support for them. Pour plus d’informations, consultez les sections prise en charge d' index implicite et prise en charge de plage implicite de la proposition.For more information, see the Implicit Index support and Implicit Range support sections of the feature proposal note. Les plages utilisant la prise en charge de plage implicite retournent le même type de séquence que la séquence source.Ranges using implicit range support return the same sequence type as the source sequence.

Par exemple, les types .NET suivants prennent en charge les index et les plages : Array, String, Span<T>et ReadOnlySpan<T>.For example, the following .NET types support both indices and ranges: Array, String, Span<T>, and ReadOnlySpan<T>. Le List<T> prend en charge les index mais ne prend pas en charge les plages.The List<T> supports indices but doesn't support ranges.

Scénarios pour les index et les plagesScenarios for indices and ranges

L’utilisation de plages et d’index est fréquente pour effectuer une analyse sur une sous-plage d’une séquence entière.You'll often use ranges and indices when you want to perform some analysis on subrange of an entire sequence. La nouvelle syntaxe permet de mieux lire la sous-plage exactement impliquée.The new syntax is clearer in reading exactly what subrange is involved. La fonction locale MovingAverage prend un Range comme argument.The local function MovingAverage takes a Range as its argument. La méthode énumère ensuite simplement cette plage lors du calcul des valeurs minimale, maximale et moyenne.The method then enumerates just that range when calculating the min, max, and average. Essayez le code suivant dans votre projet :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 {r.Start} to {r.End}:    \tMin: {min},\tMax: {max},\tAverage: {average}");
}

for (int start = 0; start < sequence.Length; start += 100)
{
    Range r = ^(start + 10)..^start;
    var (min, max, average) = MovingAverage(sequence, r);
    Console.WriteLine($"From {r.Start} to {r.End}:  \tMin: {min},\tMax: {max},\tAverage: {average}");
}

(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();

Vous pouvez télécharger le code terminé à partir du dépôt GitHub dotnet/samples.You can download the completed code from the dotnet/samples repository.