LinqとCountの効率
- C# - 09.07/21
IEnumerableを受け取ってのReverse(), Count(), ElementAt(), Last()は普通に考えると先頭から舐めるので効率がよろしくない。じゃあLinqの実装はどうなってるかというとSystem.Core.dllを眺めると
// Reverse ICollection<TElement> is2 = source as ICollection<TElement>; // ElementAt IList<TSource> list = source as IList<TSource>; // Count ICollection<TSource> is2 = source as ICollection<TSource>; // Last IList<TSource> list = source as IList<TSource>;
というわけで、IListを実装しているものなら、ちゃんと変換してくれているので大丈夫。Count()なんかは普通にLength/Countを使うから別にどうでもいいって話なのですが、Last()は[hoge.Length - 1]って書くのは嫌なので、こうして安心して使えると嬉しい話。まあ、こんなことは過去何回も話題に上っているのですが、一応自分で確認しておかないとね、ということで。
MSDNのCountの説明にはICollectionを実装してるとそれ使う、って書いてあるけど、Lastのページには何も書いていなくて困ります。内部でisだのasだのやってゴニョゴニョしてるのなら、そのことも全部記載して欲しいなあ。
といったことを何故突然というと、C#にもほしい ~rubyのeach_with_index~ - SEの勉強日記という記事を見かけたので。Count()のうえにElementAt()のラッシュというのは、IListだけならいいんですけどIEnumerableで拡張メソッドを作っているので、少しよろしくない。
public static class Extension { public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { foreach (var item in source) { action(item); } } public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action) { var index = 0; foreach (var item in source) { action(item, index++); } } } class Program { static void Main(string[] args) { Enumerable.Range(5, 6).ForEach((item, index) => Console.WriteLine("item={0} index={1}", item, index)); } }
という風にしたほうがいいと思われます。まあ、あと、new List()なんてやるぐらいなら.ToList()かしらん。
