C#でできる配列の最後(末尾)の要素を取得する方法を8パターンと速度比較しました。
速度の速い順に紹介します。まずは速度比較をご覧ください。
配列の最後(末尾)の要素を取得する速度比較
まず膨大な長さの配列を作成します。(配列作成の時間は含まない)
検証方法としては、その配列の最後(末尾)の要素を取得する前後のタイムスパンを計測し比較します。
.NET6.0環境で配列の長さ1000万の速度比較
int max = 10000000;
var arr = Enumerable.Range(0, max).Select(x => x.ToString()).ToArray();
0-10000000までをLinqのSelect関数を使ってstring[]を作っています。
取得方法 | 処理時間(ミリ秒) |
---|---|
[^1] | 00:00:00.0000001 |
IEnumerable<out T>.ElementAt(IEnumerable<out T>.Count()-1) | 00:00:00.0000003 |
[IEnumerable<out T>.Count()-1] | 00:00:00.0000151 |
IEnumerable<out T>.ElementAt(Array.Length-1) | 00:00:00.0000195 |
IEnumerable<out T>.Last() | 00:00:00.0000474 |
[Array.Length-1] | 00:00:00.0017928 |
IEnumerable<out T>.Reverse().First() | 00:00:00.0293328 |
.NET6.0環境で配列の長さ1億の速度比較
int max = 10000000;
var arr = Enumerable.Range(0, max).Select(x => x.ToString()).ToArray();
0-100000000までをLinqのSelect関数を使ってstring[]を作っています。※先ほどの10倍です。
取得方法 | 処理時間(ミリ秒) |
---|---|
[^1] | 00:00:00.0000002 |
IEnumerable<out T>.ElementAt(IEnumerable<out T>.Count()-1) | 00:00:00.0000013 |
[IEnumerable<out T>.Count()-1] | 00:00:00.0004116 |
IEnumerable<out T>.ElementAt(Array.Length-1) | 00:00:00.0011164 |
IEnumerable<out T>.Last() | 00:00:00.0054014 |
[Array.Length-1] | 00:00:00.3154145 |
IEnumerable<out T>.Reverse().First() | 00:00:06.4343751 |
配列の最後(末尾)の要素を取得する方法
計8パターンを紹介します。組み合わせによって他にもあるかもしれませんが、できるだけシンプルなものにしています。
[^1] インデクサにindex from end 演算子の 「^」を使う方法
var value = arr[^1];
C#8.0から追加されたindex from end 演算子の 「^」を使います。2019年からリリースされ、 .NET Core 3.0/.NET Standard 2.1 以降になります。
「^」はシーケンスの末尾から相対的なインデックスを指定します。
つまり、arr[^1]ということは、arr[arr.Length-1]と同意味となります。
現時点で処理速度は最速になります。
IEnumerable<out T>.ElementAt(IEnumerable<out T>.Count()-1)
var value = arr.ElementAt(arr.Count() - 1);
.NET Framework 3.5(2008年)以上で使用可能。統合言語クエリ (Language INtegrated Query; LINQ)のElementAt()とCount()を組み合わせた取得の仕方です。
1億の配列数では、Lengthプロパティとインデクサを組み合わせたarr[arr.Length-1]よりも処理速度が速い結果になり、予想をぶち壊されました。とはいえ、使用する関数名が長いので多少早くてもわざわざ使わない気持ちになります。
[IEnumerable<out T>.Count()-1] インデクサーにLinqのCount()を使用
var value = arr[arr.Count() - 1];
.NET Framework 3.5(2008年)以上で使用可能。統合言語クエリ (Language INtegrated Query; LINQ)のCount()とインデクサーを組み合わせた取得の仕方です。arr[arr.Length-1]と同意味となります。
どうやら1億ともなるとArray.Lengthプロパティが時間がかかっているのかもしれません。Count()の方が早かったです。
IEnumerable<out T>.ElementAt(Array.Length-1)
var value = arr.ElementAt(arr.Length - 1);
.NET Framework 3.5(2008年)以上で使用可能。統合言語クエリ (Language INtegrated Query; LINQ)のElementAt()とArray.Lengthプロパティを組み合わせた取得の仕方です。
IEnumerable<out T>.Last()
var value = arr.Last();
.NET Framework 3.5(2008年)以上で使用可能。統合言語クエリ (Language INtegrated Query; LINQ)のLast()を使用した方法です。
配列の最後を取得したいというやりたいことがストレートに伝わります。
数年前は遅かった印象でしたが、十分早くなったと思います。
[Array.Length-1]
var value = arr[arr.Length - 1];
定番中の定番のインデクサーとArray.Lengthプロパティを使った方法です。初期のバージョンから使用できます。
他の取得方法の処理スピードが上がったせいか、1億もの長さになってくると遅く感じます。
IEnumerable<out T>.Reverse().First()
var value = arr.Reverse().First();
.NET Framework 3.5(2008年)以上で使用可能。統合言語クエリ (Language INtegrated Query; LINQ)のReverse()とFirst()を組み合わせた取得の仕方です。配列の順序を逆転させ最初の要素を取得します。
数年前はLast()よりも早かった印象があったのですが、今回の計測では遅いです。
遅いためもはや使う必要もないです。
まとめ 圧倒的に処理速度が速く文字数の少ない[^1]を使いましょう!
圧倒的に処理速度が速く文字数の少ない[^1]を使いましょう!
2019年以前のバージョンでは使えないのでその場合は見た目と速度のバランスの良いIEnumerable<out T>.Last()か[Array.Length-1]で十分と思います。その他処理速度が速いものもおすすめです。