[C#] C #: الحصول على القيم القصوى والدنيا للخصائص التعسفية لجميع العناصر في القائمة


Answers

(تحرير لتعكس .NET 2.0 الجواب، و لينبريدج في VS2005 ...)

هناك ثلاث حالات هنا - على الرغم من أن أوب لديها فقط .NET 2.0، قد تواجه الآخرين الذين يواجهون نفس المشكلة ...

1) استخدام .NET 3.5 و C # 3.0: استخدام لينق إلى كائنات مثل هذا:

decimal maxWeight = list.Max(thing => thing.Weight);
decimal minWeight = list.Min(thing => thing.Weight);

2) استخدام .NET 2.0 و C # 3.0: استخدام لينبريدج و نفس التعليمات البرمجية

3) باستخدام .NET 2.0 و C # 2.0: استخدام لينبريدج وطرق مجهولة:

decimal maxWeight = Enumerable.Max(list, delegate(IThing thing) 
    { return thing.Weight; }
);
decimal minWeight = Enumerable.Min(list, delegate(IThing thing)
    { return thing.Weight; }
);

(ليس لدي مترجم C # 2.0 لتسليم لاختبار ما سبق - إذا كان يشكو من تحويل غامض، ويلقي المندوب إلى فونك <إيثينغ، عشري>.)

لينبريدج سوف تعمل مع VS2005، ولكنك لا تحصل على طرق التمديد، تعبيرات لامدا، تعبيرات الاستعلام الخ. الترحيل بوضوح إلى C # 3 هو خيار أجمل، ولكن كنت تفضل استخدام لينبريدج لتنفيذ نفس الوظيفة نفسي.

كل هذه الاقتراحات تنطوي على المشي قائمة مرتين إذا كنت في حاجة للحصول على حد أقصى والحد الأدنى. إذا كنت قد حصلت على الوضع حيث كنت تحميل من القرص كسول أو شيء من هذا القبيل، وتريد لحساب عدة مجاميع دفعة واحدة، قد ترغب في النظر في بلدي "دفع لينق" رمز في ميسكوتيل . (الذي يعمل مع .NET 2.0 كذلك.)

Question

لدي قائمة المتخصصة التي تحمل البنود من نوع IThing :

public class ThingList : IList<IThing>
{...}

public interface IThing
{
    Decimal Weight { get; set; }
    Decimal Velocity { get; set; }
    Decimal Distance { get; set; }
    Decimal Age { get; set; }
    Decimal AnotherValue { get; set; }

    [...even more properties and methods...]
}

أحيانا أحتاج إلى معرفة الحد الأقصى أو الحد الأدنى من خاصية معينة من كل الأشياء في القائمة. بسبب "تيل دو نوت أسك" نسمح للقائمة رقم:

public class ThingList : IList<IThing>
{
    public Decimal GetMaximumWeight()
    {
        Decimal result = 0;
        foreach (IThing thing in this) {
            result = Math.Max(result, thing.Weight);
        }
        return result;
    }
}

هذا لطيف جدا. ولكن أحيانا أحتاج إلى الحد الأدنى من الوزن، وأحيانا أقصى سرعة وهلم جرا. أنا لا أريد GetMaximum*()/GetMinimum*() الزوج لكل خاصية واحدة.

وسيكون أحد الحلول هو التفكير. شيء مثل (عقد أنفك، رائحة رمز قوية!):

Decimal GetMaximum(String propertyName);
Decimal GetMinimum(String propertyName);

هل هناك أي طرق أفضل وأقل رائحة كريهة لتحقيق ذلك؟

شكرا، اريك

تحرير:Matt: .Net 2.0

الاستنتاج: لا توجد طريقة أفضل ل. نت 2.0 (مع فيسوال ستوديو 2005). ربما يجب علينا الانتقال إلى .Net 3.5 و فيسوال ستوديو 2008 في وقت ما قريبا. شكرا، يا رفاق.

الاستنتاج: هناك طرق مختلفة التي هي أفضل بكثير من التفكير. اعتمادا على وقت التشغيل و C # الإصدار. إلقاء نظرة على جون سكيتس الإجابة عن الاختلافات. جميع الإجابات هي مفيدة جدا.

سأذهب لاقتراح سكليفز (طرق مجهولة). هناك العديد من مقتطفات الشفرة من أشخاص آخرين (كونراد رودولف، مات هاميلتون و كوينكوان) التي تنفذ فكرة سكليفز. يمكنني فقط "قبول" إجابة واحدة، للأسف.

شكرا جزيلا. يمكنك أن تشعر كل "مقبولة"، على عكس سكليفس فقط يحصل على الاعتمادات ؛-)




إذا كنت تستخدم .NET 3.5، لماذا لا تستخدم لامبداس؟

public Decimal GetMaximum(Func<IThing, Decimal> prop) {
    Decimal result = Decimal.MinValue;
    foreach (IThing thing in this)
        result = Math.Max(result, prop(thing));

    return result;
}

الاستعمال:

Decimal result = list.GetMaximum(x => x.Weight);

وهذا مكتوب بقوة وكفاءة. هناك أيضا طرق الإرشاد التي تفعل بالفعل هذا بالضبط.




وهنا محاولة، وذلك باستخدام C # 2.0، في فكرة سكيلوز.

public delegate T GetPropertyValueDelegate<T>(IThing t);

public T GetMaximum<T>(GetPropertyValueDelegate<T> getter)
    where T : IComparable
{
    if (this.Count == 0) return default(T);

    T max = getter(this[0]);
    for (int i = 1; i < this.Count; i++)
    {
        T ti = getter(this[i]);
        if (max.CompareTo(ti) < 0) max = ti;
    }
    return max;
}

يمكنك استخدامه مثل هذا:

ThingList list;
Decimal maxWeight = list.GetMaximum(delegate(IThing t) { return t.Weight; });



ماذا عن حل .Net 2 المعمم؟

public delegate A AggregateAction<A, B>( A prevResult, B currentElement );

public static Tagg Aggregate<Tcoll, Tagg>( 
    IEnumerable<Tcoll> source, Tagg seed, AggregateAction<Tagg, Tcoll> func )
{
    Tagg result = seed;

    foreach ( Tcoll element in source ) 
        result = func( result, element );

    return result;
}

//this makes max easy
public static int Max( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr > prev ? curr : prev; } );
}

//but you could also do sum
public static int Sum( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr + prev; } );
}