Dizinler ve aralıklar

Aralıklar ve dizinler, bir dizideki tek öğelere veya aralıklara erişmek için kısa bir söz dizimi sağlar.

Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:

  • Dizideki aralıklar için söz dizimini kullanın.
  • Örtük olarak bir Rangetanımlayın.
  • Her dizinin başlangıcı ve sonu için tasarım kararlarını anlayın.
  • ve Range türleri için Index senaryoları öğrenin.

Dizinler ve aralıklar için dil desteği

Dizinler ve aralıklar, bir dizideki tek öğelere veya aralıklara erişmek için kısa bir söz dizimi sağlar.

Bu dil desteği iki yeni türe ve iki yeni işleçe dayanır:

Dizinler için kurallarla başlayalım. bir dizi sequencedüşünün. Dizin 0 ile aynıdır sequence[0]. Dizin ^0 ile aynıdır sequence[sequence.Length]. İfade sequence[^0] , tıpkı olduğu gibi sequence[sequence.Length] bir özel durum oluşturur. herhangi bir sayı niçin dizin ^n ile aynıdır sequence.Length - n.

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

Dizinle birlikte ^1 son sözcüğü alabilirsiniz. Başlatmanın altına aşağıdaki kodu ekleyin:

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

Aralık, aralığın başlangıcını ve sonunu belirtir. Aralığın başlangıcı kapsayıcıdır, ancak aralığın sonu özeldir; bu, başlangıcın aralığa dahil olduğu ancak sonun aralığa dahil olmadığı anlamına gelir. Aralık [0..^0] , aralığın tamamını temsil ettiği gibi [0..sequence.Length] aralığın tamamını da temsil eder.

Aşağıdaki kod "quick", "brown" ve "fox" sözcükleriyle bir alt düzen oluşturur. aracılığıyla words[3]içerirwords[1]. öğesi words[4] aralıkta değil.

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

Aşağıdaki kod , "lazy" ve "dog" ile aralığı döndürür. ve words[^1]içerirwords[^2]. Bitiş dizini words[^0] dahil değildir. Aşağıdaki kodu da ekleyin:

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

Aşağıdaki örneklerde başlangıç, bitiş veya her ikisi için açık uçlu aralıklar oluşturulur:

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

Aralıkları veya dizinleri değişken olarak da bildirebilirsiniz. Değişkeni daha sonra ve ] karakterlerinin [ içinde kullanılabilir:

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

Aşağıdaki örnekte bu seçeneklerin birçok nedeni gösterilmiştir. Farklı birleşimleri denemek için , yve z değerlerini değiştirinx. Deneme yaparken, geçerli birleşimler x için değerinden küçük yve y değerinden z küçük değerleri kullanın. Aşağıdaki kodu yeni bir yönteme ekleyin. Farklı birleşimleri deneyin:

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

Yalnızca diziler dizinleri ve aralıkları desteklemez. Dizinleri ve aralıkları dize, Span<T>veya ReadOnlySpan<T>ile de kullanabilirsiniz.

Örtük aralık işleci ifade dönüştürmeleri

Aralık işleci ifadesinin söz dizimini kullanırken, derleyici başlangıç ve bitiş değerlerini örtük olarak ve Index değerlerine dönüştürür, yeni Range bir örnek oluşturur. Aşağıdaki kod, aralık işleci ifadesinin söz diziminden örnek örtük dönüştürmeyi ve buna karşılık gelen açık alternatifi gösterir:

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'

Önemli

değeri negatif olduğunda'dan Int32Index oluşturmaya ArgumentOutOfRangeException yönelik örtük dönüştürmeler. Benzer şekilde, Index parametre negatif olduğunda value oluşturucu bir ArgumentOutOfRangeException oluşturur.

Dizinler ve aralıklar için tür desteği

Dizinler ve aralıklar, tek bir öğeye veya bir dizideki öğe aralığına erişmek için net, kısa söz dizimi sağlar. Dizin ifadesi genellikle bir dizinin öğelerinin türünü döndürür. Aralık ifadesi genellikle kaynak diziyle aynı dizi türünü döndürür.

Veya Range parametresine sahip bir dizin oluşturucu sağlayan herhangi bir Indextür, sırasıyla dizinleri veya aralıkları açıkça destekler. Tek Range bir parametre alan dizin oluşturucu, gibi System.Span<T>farklı bir dizi türü döndürebilir.

Önemli

Aralık işlecini kullanan kodun performansı, sıra işleneninin türüne bağlıdır.

Aralık işlecinin zaman karmaşıklığı sıra türüne bağlıdır. Örneğin, dizi bir string veya diziyse, sonuç girişin belirtilen bölümünün bir kopyasıdır, bu nedenle zaman karmaşıklığı O(N) olur (burada N aralığın uzunluğudur). Öte yandan, veya iseSystem.Span<T>, sonuç aynı yedekleme deposuna başvurur; başka bir deyişle kopya yoktur ve işlem O(1)'dir.System.Memory<T>

Bu, zaman karmaşıklığının yanı sıra ek ayırmalara ve kopyalara neden olarak performansı etkiler. Performansa duyarlı kodda, aralık işleci bunlar için ayırmadığından sıra türü olarak veya Memory<T> kullanmayı Span<T> göz önünde bulundurun.

türü, adlı veya erişilebilir bir alıcıya ve dönüş türüne intsahip bir özelliği varsa sayılabilir.CountLength Dizinleri veya aralıkları açıkça desteklemeyen sayılabilir bir tür, bunlar için örtük bir destek sağlayabilir. Daha fazla bilgi için özellik teklifi notunun Örtük Dizin desteği ve Örtük Aralık desteği bölümlerine bakın. Örtük aralık desteği kullanan aralıklar, kaynak diziyle aynı dizi türünü döndürür.

Örneğin, aşağıdaki .NET türleri hem dizinleri hem de aralıkları destekler: String, Span<T>ve ReadOnlySpan<T>. dizinleri List<T> destekler ancak aralıkları desteklemez.

Array daha fazla nüanslı davranışa sahiptir. Tek boyutlu diziler hem dizinleri hem de aralıkları destekler. Çok boyutlu diziler dizin oluşturucuları veya aralıkları desteklemez. Çok boyutlu bir dizinin dizin oluşturucusunun tek bir parametre değil, birden çok parametresi vardır. Dizi dizisi olarak da adlandırılan pürüzlü diziler hem aralıkları hem de dizin oluşturucuları destekler. Aşağıdaki örnekte, pürüzlü bir dizinin dikdörtgen alt bölümü nasıl yinelenir gösterilmektedir. İlk ve son üç satırı ve seçilen her satırdaki ilk ve son iki sütunu hariç tutarak ortadaki bölümü yineler:

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

Her durumda, için Array aralık işleci döndürülen öğeleri depolamak için bir dizi ayırır.

Dizinler ve aralıklar için senaryolar

Daha büyük bir sıranın bir bölümünü analiz etmek istediğinizde genellikle aralıkları ve dizinleri kullanırsınız. Yeni söz dizimi, dizinin tam olarak hangi bölümünün dahil olduğunu okurken daha nettir. Yerel işlev MovingAverage bağımsız değişkeni olarak bir Range alır. Yöntemi daha sonra min, max ve average değerlerini hesaplarken yalnızca bu aralığı numaralandırır. Projenizde aşağıdaki kodu deneyin:

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

Aralık Dizinleri ve Dizileriyle ilgili Bir Not

Bir diziden aralık alınırken, sonuç başvurulmak yerine ilk diziden kopyalanan bir dizidir. Sonuçta elde edilen dizideki değerlerin değiştirilmesi, ilk dizideki değerleri değiştirmez.

Örneğin:

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

Ayrıca bkz.