سؤال

أنا أعمل مع قاعدة تعليمات برمجية حيث يجب البحث في القوائم بشكل متكرر عن عنصر واحد.

هل يعد استخدام المسند و Find () أسرع من إجراء التعداد يدويًا في القائمة؟

على سبيل المثال:

string needle = "example";
FooObj result = _list.Find(delegate(FooObj foo) {
    return foo.Name == needle;
});

ضد.

string needle = "example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)
        return foo;
}

في حين أنهما متساويان في الأداء الوظيفي، هل هما متساويان في الأداء أيضًا؟

هل كانت مفيدة؟

المحلول

فهي ليست متساوية في الأداء.تتطلب طريقة Find () استدعاء أسلوب (في هذه الحالة مفوض) لكل عنصر في القائمة.استدعاء الأسلوب ليس مجانيًا وهو كذلك نسبياً باهظة الثمن بالمقارنة مع المقارنة المضمنة.لا يتطلب إصدار foreach أي استدعاء أسلوب إضافي لكل كائن.

ومع ذلك، لن أختار واحدًا أو الآخر بناءً على الأداء حتى أقوم بالفعل بتوصيف الكود الخاص بي ووجدت أن هذا يمثل مشكلة.لم أجد بعد مقدار الحمل لهذا السيناريو الذي يمثل مشكلة "مسار سريع" للتعليمات البرمجية التي كتبتها وأنا أستخدم هذا النمط كثيرًا مع Find وطرق أخرى مماثلة.

نصائح أخرى

وإذا كان البحث قائمتك بطيئة جدا كما هو بين، وربما يمكنك أن تفعل أفضل من البحث الخطي. إذا كنت يمكن أن تبقي على القائمة التي تم فرزها، يمكنك استخدام البحث الثنائي للعثور على عنصر في O (إل جي ن) وقت.

إذا كنت تبحث عن كله الكثير، التفكير في استبدال تلك القائمة مع قاموس لمؤشر الأشياء الخاصة بك بالاسم.

ومن الناحية الفنية، وأداء وقت التشغيل من النسخة مندوب ستكون أسوأ قليلا من نسخة أخرى - ولكن في معظم الحالات، سيكون من الصعب تصور أي فرق

وأكثر أهمية (IHMO) هو الأداء في الوقت مدونة القدرة على كتابة ما تريد، وليس كيف تريد. هذا يحدث فرقا كبيرا في الصيانة.

وهذا الرمز الأصلي:

string needle = "example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)        
        return foo;
}

ويتطلب أي معيل لقراءة رمز ونفهم أن كنت تبحث عن عنصر معين.

وهذا الرمز

string needle = "example";
return _list.Find(
    delegate(FooObj foo) 
    {
        return foo.Name == needle;
    });

ويوضح أن كنت تبحث عن عنصر معين - أسرع للفهم

وأخيرا، هذا الرمز، وذلك باستخدام ميزات من C # 3.0:

string needle = "example";
return _list.Find( foo => foo.Name == needle);

ويفعل نفس الشيء، ولكن في سطر واحد وهذا أسرع لقراءة وفهم (وأيضا، بمجرد فهم <لأ href = "https://stackoverflow.com/questions/150129/what-is-a-lambda "> تعبيرات لامدا ، على أي حال).

في ملخص، بالنظر إلى أن أداء البدائل يساوي تقريبا، اختيار واحد أن يجعل رمز أسهل للقراءة والمحافظة عليها.

"أنا أعمل مع قاعدة التعليمات البرمجية حيث القوائم يحتاج لأن يكون تم البحث عنها بشكل متكرر لعنصر واحد"

من الأفضل تغيير بنية البيانات الخاصة بك لتصبح قاموسًا بدلاً من القائمة للحصول على أداء أفضل

وسئل اسئلة مشابهة لList.ForEach مقابل foreach-التكرار ( foreach مقابل someList.Foreach () {} ).

في هذه الحالة List.ForEach كان أسرع قليلا.

وكما أشار جاريد بها، هناك اختلافات.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top