次のように使用するIEnumerable拡張MaxByがあります
var longest = new [] {"cat", "dogs", "nit" }.MaxBy(x=>x.Count())
する必要があります
"dogs"
実装あり*強調テキスト*
public static T MaxBy<T,M>(this IEnumerable<T> This, Func<T,M> selector)
where M : IComparable
{
return This
.Skip(1)
.Aggregate
( new {t=This.First(), m = selector(This.First())}
, (a, t) =>
{
var m = selector(t);
if ( m.CompareTo(a.m) > 0)
{
return new { t, m };
}
else
{
return a;
}
}
, a => a.t);
}
それは非常にエレガントで純粋に機能的ですが、問題があります。参照型でガベージ コレクションを必要とする匿名オブジェクトを使用しています。長さの IEnumerable を走査する最悪のケースでは、NI は N 個のメモリ割り当てを行い、N 個のオブジェクトはガベージ コレクションを必要とします。
外部の変更可能なアキュムレータを使用するコードを書くこともできますが、審美的には、私が持っているパターンに固執することを好みます。
しかし、私の懸念は実際には問題ですか?.Net 世代別ガベージ コレクターは、これらのオブジェクトが非常に短命であり、一度に 1 つしか存在しないことを識別し、何が起こっているかを最適化しますか? それとも、匿名オブジェクトを使用する代わりに、アキュムレータを保持するカスタム値型 ( struct ) を作成する方がよいでしょうか。
** 編集 **
これは明らかに非機能的な方法です。
public static T MaxBy<T,M>(this IEnumerable<T> This, Func<T,M> selector)
where M : IComparable
{
var t = This.First();
var max = selector(t);
foreach (var item in This.Skip(1))
{
var m = selector(item);
if ( m.CompareTo(max) > 0)
{
max = m;
t = item;
}
}
return t;
}