1

次のように使用する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;
}
4

1 に答える 1