詳解c#索引(Index)和范圍(Range)
范圍和索引為訪問序列中的單個(gè)元素或范圍提供了簡潔的語法。
在本教程中,你將了解:
- 對(duì)某個(gè)序列中的范圍使用該語法。
- 了解每個(gè)序列開頭和末尾的設(shè)計(jì)決策。
- 了解 Index 和 Range 類型的應(yīng)用場景。
對(duì)索引和范圍的語言支持
此語言支持依賴于兩個(gè)新類型和兩個(gè)新運(yùn)算符:
- System.Index 表示一個(gè)序列索引。
- 來自末尾運(yùn)算符 ^ 的索引,指定一個(gè)索引與序列末尾相關(guān)。
- System.Range 表示序列的子范圍。
- 范圍運(yùn)算符 ..,用于指定范圍的開始和末尾,就像操作數(shù)一樣。
讓我們從索引規(guī)則開始。 請(qǐng)考慮數(shù)組 sequence。 0 索引與 sequence[0] 相同。 ^0 索引與 sequence[sequence.Length] 相同。 表達(dá)式 sequence[^0] 不會(huì)引發(fā)異常,就像 sequence[sequence.Length] 一樣。 對(duì)于任何數(shù)字 n,索引 ^n 與 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
可以使用 ^1 索引檢索最后一個(gè)詞。 在初始化下面添加以下代碼:
Console.WriteLine($"The last word is {words[^1]}");
范圍指定范圍的開始和末尾。 范圍是排除的,也就是說“末尾”不包含在范圍內(nèi)。 范圍 [0..^0] 表示整個(gè)范圍,就像 [0..sequence.Length] 表示整個(gè)范圍。
以下代碼創(chuàng)建了一個(gè)包含單詞“quick”、“brown”和“fox”的子范圍。 它包括 words[1] 到 words[3]。 元素 words[4] 不在該范圍內(nèi)。 將以下代碼添加到同一方法中。 將其復(fù)制并粘貼到交互式窗口的底部。
string[] quickBrownFox = words[1..4];
foreach (var word in quickBrownFox)
Console.Write($"< {word} >");
Console.WriteLine();
以下代碼使用“l(fā)azy”和“dog”返回范圍。 它包括 words[^2] 和 words[^1]。 結(jié)束索引 words[^0] 不包括在內(nèi)。 同樣添加以下代碼:
string[] lazyDog = words[^2..^0];
foreach (var word in lazyDog)
Console.Write($"< {word} >");
Console.WriteLine();
下面的示例為開始和/或結(jié)束創(chuàng)建了開放范圍:
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();
還可以將范圍或索引聲明為變量。 然后可以在 [ 和 ] 字符中使用該變量:
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();
下面的示例展示了使用這些選項(xiàng)的多種原因。 請(qǐng)修改 x、y 和 z 以嘗試不同的組合。 在進(jìn)行實(shí)驗(yàn)時(shí),請(qǐng)使用 x 小于 y且 y 小于 z 的有效組合值。 在新方法中添加以下代碼。 嘗試不同的組合:
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]}");
索引和范圍的類型支持
索引和范圍提供清晰、簡潔的語法來訪問序列中的單個(gè)元素或元素的范圍。 索引表達(dá)式通常返回序列元素的類型。 范圍表達(dá)式通常返回與源序列相同的序列類型。
若任何類型提供帶 Index 或 Range 參數(shù)的索引器,則該類型可分別顯式支持索引或范圍。 采用單個(gè) Range 參數(shù)的索引器可能會(huì)返回不同的序列類型,如 System.Span<T>。
重要
使用范圍運(yùn)算符的代碼的性能取決于序列操作數(shù)的類型。
范圍運(yùn)算符的時(shí)間復(fù)雜度取決于序列類型。 例如,如果序列是 string 或數(shù)組,則結(jié)果是輸入中指定部分的副本,因此,時(shí)間復(fù)雜度為 O(N)(其中 N 是范圍的長度)。 另一方面,如果它是System.Span<T>或System.Memory<T>,則結(jié)果引用相同的后備存儲(chǔ),這意味著沒有副本且操作為 O(1)。
除了時(shí)間復(fù)雜度外,這還會(huì)產(chǎn)生額外的分配和副本,從而影響性能。 在性能敏感的代碼中,考慮使用Span<T>或Memory<T>作為序列類型,因?yàn)椴粫?huì)為其分配范圍運(yùn)算符。
若類型包含名稱為 Length 或 Count 的屬性,屬性有可訪問的 Getter 并且其返回類型為 int,則此類型為可計(jì)數(shù)類型。**** 不顯式支持索引或范圍的可計(jì)數(shù)類型可能為它們提供隱式支持。 有關(guān)詳細(xì)信息,請(qǐng)參閱功能建議說明的隱式索引支持和隱式范圍支持部分。 使用隱式范圍支持的范圍將返回與源序列相同的序列類型。
例如,以下 .NET 類型同時(shí)支持索引和范圍:String、Span<T> 和 ReadOnlySpan<T>。 List<T> 支持索引,但不支持范圍。
Array 具有更多的微妙行為。 單個(gè)維度數(shù)組同時(shí)支持索引和范圍。 多維數(shù)組則不支持。 多維數(shù)組的索引器具有多個(gè)參數(shù),而不是一個(gè)參數(shù)。 交錯(cuò)數(shù)組(也稱為數(shù)組的數(shù)組)同時(shí)支持范圍和索引器。 下面的示例演示如何循環(huán)訪問交錯(cuò)數(shù)組的矩形子節(jié)。 它循環(huán)訪問位于中心的節(jié),不包括前三行和后三行,以及每個(gè)選定行中的前兩列和后兩列:
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($"{cell}, ");
}
Console.WriteLine();
}
在所有情況下,Array 的范圍運(yùn)算符都會(huì)分配一個(gè)數(shù)組來存儲(chǔ)返回的元素。
索引和范圍的應(yīng)用場景
要分析較大序列的一部分時(shí),通常會(huì)使用范圍和索引。 在準(zhǔn)確讀取所涉及的序列部分這一方面,新語法更清晰。 本地函數(shù) MovingAverage 以 Range 為參數(shù)。 然后,該方法在計(jì)算最小值、最大值和平均值時(shí)僅枚舉該范圍。 在項(xiàng)目中嘗試以下代碼:
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();
以上就是詳解c#索引(Index)和范圍(Range)的詳細(xì)內(nèi)容,更多關(guān)于c# 索引和范圍的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#使用AutoUpdater.NET實(shí)現(xiàn)程序自動(dòng)更新
開發(fā)桌面應(yīng)用程序的時(shí)候,經(jīng)常會(huì)因?yàn)樾略龉δ苄枨蠡蛐迯?fù)已知問題,要求客戶更新應(yīng)用程序,在.Net體系中采用?AutoUpdater.NET?組件可以非常便捷的實(shí)現(xiàn)這一功能,需要的朋友可以參考下2024-02-02
C#實(shí)現(xiàn)的sqlserver操作類實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的sqlserver操作類,結(jié)合具體實(shí)例形式分析了C#針對(duì)sqlserver數(shù)據(jù)庫進(jìn)行連接、查詢、更新、關(guān)閉等相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
NumberToUpper數(shù)字轉(zhuǎn)中文詳解
本文介紹NumberToUpper數(shù)字轉(zhuǎn)中文的方法,大家參考使用吧2013-12-12
C#實(shí)現(xiàn)將記事本中的代碼編譯成可執(zhí)行文件的方法
這篇文章主要介紹了C#實(shí)現(xiàn)將記事本中的代碼編譯成可執(zhí)行文件的方法,很實(shí)用的技巧,需要的朋友可以參考下2014-08-08
C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼
這篇文章主要介紹了C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-12-12
C#?DateTime.Now.ToString()?用法示例講解
這篇文章主要介紹了C#?DateTime.Now.ToString()?用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01

