Megosztás a következőn keresztül:


Indexek és tartományok

A tartományok és indexek tömör szintaxist biztosítanak az egyes elemek vagy tartományok sorozatban való eléréséhez.

Az oktatóanyag segítségével megtanulhatja a következőket:

  • Használja a sorozatban lévő tartományok szintaxisát.
  • Implicit módon definiáljon egy Range.
  • Megismerheti az egyes sorozatok elején és végének tervezési döntéseit.
  • Ismerje meg a forgatókönyveket és Range a Index típusokat.

Indexek és tartományok nyelvi támogatása

Az indexek és a tartományok tömör szintaxist biztosítanak az egyes elemek vagy tartományok sorozatban való eléréséhez.

Ez a nyelvi támogatás két új típusra és két új operátorra támaszkodik:

Kezdjük az indexek szabályaival. Fontolja meg a tömböt sequence. Az 0 index megegyezik sequence[0]a . Az ^0 index megegyezik sequence[sequence.Length]a . A kifejezés sequence[^0] kivételt okoz, ahogy sequence[sequence.Length] az is. Bármely szám nesetén az index ^n megegyezik sequence.Length - na .

string[] words = [
                // 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

Az utolsó szót lekérheti az ^1 indexszel. Adja hozzá a következő kódot az inicializálás alatt:

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

A tartomány egy tartomány kezdetét és végét határozza meg. A tartomány kezdete magában foglalja a tartományt, de a tartomány vége kizárólagos, ami azt jelenti, hogy a kezdő a tartomány része, de a vége nem szerepel a tartományban. A tartomány [0..^0] a teljes tartományt jelöli, ugyanúgy, mint [0..sequence.Length] a teljes tartományt.

Az alábbi kód egy altartományt hoz létre a "gyors", a "barna" és a "róka" szavakkal. Ez magában foglalja words[1] a .words[3] Az elem words[4] nincs a tartományban.

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

Az alábbi kód a "lusta" és a "kutya" tartományt adja vissza. words[^2] Tartalmazza és words[^1]. A záró index words[^0] nem szerepel a fájlban. Adja hozzá a következő kódot is:

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

Az alábbi példák olyan tartományokat hoznak létre, amelyek nyitottak a kezdéshez, a befejezéshez vagy mindkettőhöz:

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

Tartományokat vagy indexeket változóként is deklarálhat. A változó ezután a következő karaktereken ] belül [ használható:

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

Az alábbi minta számos érvet mutat be ezeknek a választási lehetőségeknek a céljából. Módosítsa x, yés z próbálja ki a különböző kombinációkat. Kísérletezéskor olyan értékeket használjon, ahol x kisebb, mint y, és y kisebb, mint z az érvényes kombinációk esetében. Adja hozzá a következő kódot egy új metódushoz. Próbálja ki a különböző kombinációkat:

int[] numbers = [..Enumerable.Range(0, 100)];
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]}");

Nemcsak a tömbök támogatják az indexeket és a tartományokat. Az indexeket és tartományokat sztringgel Span<T>vagy .ReadOnlySpan<T>

Implicit tartomány operátorkifejezéseinek konvertálása

A tartományoperátor kifejezésszintaxisának használatakor a fordító implicit módon konvertálja a kezdő és a záró értékeket, Index és ezekből létrehoz egy új Range példányt. Az alábbi kód egy példa implicit konverziót mutat be a tartomány operátorkifejezésének szintaxisából, és annak megfelelő explicit alternatíváját:

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 '{implicitRange}' equals the explicit range '{explicitRange}'");
}
// Sample output:
//     The implicit range '3..^5' equals the explicit range '3..^5'

Fontos

Implicit konverziók a Int32 negatív értéktől a dobásig IndexArgumentOutOfRangeException . Hasonlóképpen, a Index konstruktor negatív ArgumentOutOfRangeException értéket ad, amikor a value paraméter negatív.

Indexek és tartományok támogatásának beírása

Az indexek és a tartományok egyértelmű, tömör szintaxist biztosítanak, hogy egyetlen elemet vagy elemtartományt érhessenek el egy sorozatban. Az indexkifejezés általában egy sorozat elemeinek típusát adja vissza. A tartománykifejezések általában ugyanazt a sorozattípust adják vissza, mint a forrásütemezés.

Minden olyan típus, amely egy indexelőt vagy Range paramétert Index biztosít, kifejezetten támogatja az indexeket vagy tartományokat. Az egyetlen Range paramétert használó indexelők eltérő sorozattípust adhatnak vissza, például System.Span<T>.

Fontos

A kód tartomány operátorral történő teljesítménye a sorozatoperndus típusától függ.

A tartomány operátorának időösszetettsége a sorozat típusától függ. Ha például a sorozat egy string vagy tömb, akkor az eredmény a bemenet megadott szakaszának másolata, így az idő összetettsége O(N) (ahol N a tartomány hossza). Ha viszont egy System.Span<T> vagy egy System.Memory<T>, az eredmény ugyanarra a háttértárra hivatkozik, ami azt jelenti, hogy nincs másolat, és a művelet O(1).

Az idő összetettsége mellett ez további foglalásokat és másolatokat is okoz, ami hatással van a teljesítményre. A teljesítményérzékeny kódban érdemes lehet a sorozattípust használni Span<T> vagy Memory<T> használni, mivel a tartomány operátora nem foglalja le őket.

Egy típus akkor számítható meg, ha rendelkezik egy elnevezett Length tulajdonsággal, vagy Count egy akadálymentes lekérővel és egy visszatérési típussal int. Az indexeket vagy tartományokat explicit módon nem támogató megszámlálható típus implicit támogatást nyújthat számukra. További információkért tekintse meg a funkciójavaslat megjegyzésének implicit indextámogatási és implicit tartománytámogatási szakaszait. Az implicit tartománytámogatást használó tartományok ugyanazt a sorozattípust adják vissza, mint a forrásütemezés.

A következő .NET-típusok például az indexeket és a tartományokat is támogatják: String, Span<T>és ReadOnlySpan<T>. A List<T> támogatott indexek nem támogatják a tartományokat.

Array árnyaltabb viselkedést ad. Az egydimenziós tömbök az indexeket és a tartományokat is támogatják. A többdimenziós tömbök nem támogatják az indexelőket és a tartományokat. A többdimenziós tömb indexelője több paraméterrel rendelkezik, nem egyetlen paraméterrel. A szaggatott tömbök, más néven tömbök mind tartományokat, mind indexelőket támogatnak. Az alábbi példa bemutatja, hogyan lehet egy szaggatott tömb négyszögletes alszakaszát iterálni. A középen lévő szakaszt iterálja, kivéve az első és az utolsó három sort, valamint az első és az utolsó két oszlopot az egyes kijelölt sorokból:

int[][] jagged = 
[
   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
   [10,11,12,13,14,15,16,17,18,19],
   [20,21,22,23,24,25,26,27,28,29],
   [30,31,32,33,34,35,36,37,38,39],
   [40,41,42,43,44,45,46,47,48,49],
   [50,51,52,53,54,55,56,57,58,59],
   [60,61,62,63,64,65,66,67,68,69],
   [70,71,72,73,74,75,76,77,78,79],
   [80,81,82,83,84,85,86,87,88,89],
   [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($"{cell}, ");
    }
    Console.WriteLine();
}

A visszaadott elemek tárolásához Array a tartomány operátora minden esetben lefoglal egy tömböt.

Forgatókönyvek indexekhez és tartományokhoz

Gyakran használ tartományokat és indexeket, ha egy nagyobb sorozat egy részét szeretné elemezni. Az új szintaxis pontosabban beolvassa a sorozat melyik részét. A helyi függvény MovingAverage argumentumként egy függvényt Range vesz fel. A metódus ezután csak ezt a tartományt veszi számba a minimális, a maximális és az átlag kiszámításakor. Próbálja ki a következő kódot a projektben:

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

Megjegyzés a tartományindexekről és tömbökről

Ha tartományt vesz fel egy tömbből, az eredmény egy olyan tömb, amelyet a rendszer a kezdeti tömbből másol, és nem hivatkozik rá. Az eredményként kapott tömb értékeinek módosítása nem módosítja a kezdeti tömb értékeit.

Például:

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

Kapcsolódó információk