はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】LINQの「ElementAt(0) vs First()」

はじめに

プルリクのレビューをしていたところ、Enumerable.ElementAt(0)を用いてコレクションの最初の要素を指定している方がいました。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.elementat?view=net-5.0

私はいつもEnumerable.First()を使っていたので、すごい新鮮だったのですがどっちの方がパフォーマンスが良いのか気になったので調べてみました。
Enumerable.First メソッド (System.Linq) | Microsoft Docs

その結果について書き残しておきたいと思います。

結論

先に結論を行っておくとElementAtの方が性能がいいという結果になってしまいました。

海外兄貴たちがいうにはFitst()の方が早いらしいのですが、私の環境だとこのサイトのコード通りに実行してもElementAtの方が速度がでているようです。(原因は全くわからない・・・)
c# - Difference between list.First(), list.ElementAt(0) and list[0]? - Stack Overflow

実験方法

var collection = Enumerable.Range(0, 1000000);
var loop = 100000000;
var tmp = 0;

var sw = new System.Diagnostics.Stopwatch();

// Enumerable.First()
sw.Start();
for (int i = 0; i < loop; i++)
    tmp = collection.First();
sw.Stop();
Console.WriteLine($"Enumerable.First() : {sw.ElapsedMilliseconds} ms");

// Enumerable.FirstOrDefault()
sw.Restart();
for (int i = 0; i < loop; i++)
    tmp = collection.FirstOrDefault();
sw.Stop();
Console.WriteLine($"Enumerable.FirstOrDefault() : {sw.ElapsedMilliseconds} ms");

// Enumerable.ElementAt(0)
sw.Restart();
for (int i = 0; i < loop; i++)
    tmp = collection.ElementAt(0);
sw.Stop();
Console.WriteLine($"Enumerable.ElementAt(0) : {sw.ElapsedMilliseconds} ms");

// Enumerable.ElementAtOrDefault(0)
sw.Restart();
for (int i = 0; i < loop; i++)
    tmp = collection.ElementAtOrDefault(0);
sw.Stop();
Console.WriteLine($"Enumerable.ElementAtOrDefault(0) : {sw.ElapsedMilliseconds} ms");

結果

メソッド名 処理時間(ms)
First() 1864
FirstOrDefault() 1825
ElementAt(0) 1642
ElementAtOrDefault(0) 1668

(.NET Framework 4.7.2VisualStudioのコンソールプロジェクト)

f:id:hanaaaaaachiru:20201116123108p:plain
出力

さいごに

正直こんな結果になるなんて思わなくて、実験結果が信じられないですね。

何かわかる方がいらっしゃいましたらコメント等で教えてくださると嬉しいです。