كيفية إزالة الكائنات من مجموعة لا تعد ولا تحصى في حلقة [مكررة]

StackOverflow https://stackoverflow.com/questions/404557

سؤال

ينسخ

تعديل مجموعة أثناء التكرار من خلالها


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

على سبيل المثال، يفشل ما يلي، لأنه يعدل القائمة التي يتم تعدادها أثناء عملية البحث

foreach (MyObject myObject in MyListOfMyObjects)
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

لقد استخدمت طريقتين في الماضي.

لقد استبدلت foreach بحلقة for معكوسة (حتى لا أغير أي فهارس أقوم بتكرارها إذا قمت بإزالة كائن).

لقد حاولت أيضًا تخزين مجموعة جديدة من الكائنات لإزالتها داخل التكرار، ثم تكرار هذه المجموعة وإزالة الكائنات من المجموعة الأصلية.

هذه تعمل بشكل جيد، ولكن لا يشعر جميل، وكنت أتساءل عما إذا كان أي شخص قد توصل إلى المزيد رائع حل لهذه القضية

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

المحلول

هناك مفيد List<T>.RemoveAll(Predicate<T> match) الطريقة التي أعتقد أنها مصممة لهذا: http://msdn.microsoft.com/en-us/library/wdka673a.aspx

نصائح أخرى

إنه أمر بسيط نوعًا ما، ولكن عندما أخطط لحذف عناصر من IEnumerable/IList، عادةً ما أقوم بعمل نسخة:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

إنها ليست الطريقة الأكثر فعالية للقيام بذلك، ولكن من السهل قراءتها.التحسين المبكر وكل ذلك.

قم بالعكس، وقم بإنشاء قائمة جديدة:

List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
     if (!condition) myFilteredList.Add(myObject);
}

ثم استخدم القائمة الجديدة أينما كنت في حاجة إليها.

يمكنك أيضًا استخدام تعبير LINQ بسهولة، مرة أخرى، لعكس الشرط.وهذا له فائدة إضافية تتمثل في عدم إنشاء بنية جديدة، ولكن أيضًا هناك عيوب في كونها قابلة للتعداد كسولًا:

var myFilteredList = from myObject in myListOfMyObjects
                     where !condition
                     select myObject;

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

لقد عثرت للتو على هذا المنشور واعتقدت أنني سأشاركه.

void RemoveAll(object condition)  
{

    bool found = false;

    foreach(object thisObject in objects)    
    {

        if (condition)    
        {    
            objects.Remove(thisObject);

            found = true;

            break; //exit loop    
        }     
     }

    // Call again recursively

    if (found) RemoveAll(condition);

}

لا أحب فكرة الحلقة المعكوسة، نظرًا لأن ذلك يعمل فقط على هياكل بيانات معينة.

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

الأسلوب الآخر الوحيد الذي استخدمته أحيانًا هو إعادة تشغيل التكرار بالكامل عندما تجد العنصر الأول الذي تريد حذفه.إذا قمت بذلك دون العثور على أي عناصر لحذفها، فستنتهي الوظيفة.هذا غير فعال، ولكنه ضروري في بعض الأحيان إذا كان حذف عنصر واحد من المجموعة قد يؤدي إلى تغيير مجموعة العناصر التي يجب حذفها.

لدي قاموس وأريد التخلص من كل القيم.عندما يتم التخلص من كل قيمة، فإنها تزيل نفسها من القاموس مما يخلق المشكلة التي تناقشها.فعلت ما يلي:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}

أقدر أن هذا قد يكون ميتًا الآن ولكن الطريقة التي أفعل بها ذلك دائمًا هي:

foreach (MyObject myObject في MyListOfMyObjects)
{

إذا (حالة) MyListOfMyObjects.Remove(myObject);

استراحة؛

}

تتم إزالة الكائن ثم تخرج الحلقة، فيولا!

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