C# LINQ ToListのパフォーマンスについて
※これはどこかで読んだ記事の内容を参考にしたものです。参照先を忘れてしまっていて、見つけ次第リンクを貼ります。
コードを書いていると、Listの操作をすることが多いかと思います。特に、Listの中の、ある要素を一括で取り出す時なんかSelect からのToListとかそこそこ、あると思います。
public static void TestFunc()
{
var range = Enumerable.Range(1, 10000);
var list = range.Where(_ => _ % 2 == 0)
.Select(_ => (float)_)
.ToList();
}
ここで何となくToListって遅くないの?って思ったので、mono C# のListの実装を読んでみます。
mono のToList
ほー、キャストやらなんやら詰まってますね。何よりListのnew の仕方が…。
なので、少し単純化します。
static class ListExtensions
{
public static List<T> ToListEx<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
var result = new List<T>();
foreach (var t in source)
{
result.Add(t);
}
return result;
}
}
IEnumerableを拡張して、ToListの代わりにToListExを用意しました。
public static void TestFunc()
{
var range1 = Enumerable.Range(1, 10000);
var range2 = Enumerable.Range(1, 10000);
var start = DateTime.Now;
var list1 = range1.Where(_ => _ % 2 == 0)
.Select(_ => (float)_)
.ToList();
Debug.Log((double)(DateTime.Now.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond + "ms List");
start = DateTime.Now;
var list2 = range2.Where(_ => _ % 2 == 0)
.Select(_ => (float)_)
.ToListEx();
Debug.Log((double)(DateTime.Now.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond + "ms ListEx");
}
計測結果
関数 | 時間(ms) |
---|---|
ToList | 2.0469 |
ToListEx | 1.0025 |
倍程度高速化できました。Releaseビルドなど、最適化具合でどれほど意味があるのかは別として、Listとかよく使うクラスは自作してしまいたい気持ちに駆られます。