هل من الآمن حذف من قائمة الفرز أثناء التكرار

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

  •  01-10-2019
  •  | 
  •  

سؤال

سؤالي هل من الآمن أن يقوم العداد بإزالة العنصر من SortedList؟

SortedList<decimal, string> myDictionary;
// omitted code

IEnumerator<decimal, string> enum = myDictionary.GetEnumerator();

while(enum.MoveNext)
{
  // is it ok to remove here?
  myDictionary.Remove(enum.Current.Key);
}
هل كانت مفيدة؟

المحلول

سيؤدي ذلك إلى إلقاء استثناء - لا يمكنك تعديل مجموعة أثناء التكرار عليها.

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

نصائح أخرى

كما ذكرنا بالفعل ما تبحث عنه غير ممكن. ومع ذلك ، سيكون الحل البديل هو الحفاظ على قائمة العناصر المحددة للحذف ثم إزالة هذه الكلمات اللاحقة. أود أيضًا أن أختار foreach بدلا من while حلقة ، رمز أقل على سبيل المثال

var removeList = new List<decimal>();
foreach (var item in myDictionary)
{
    // have a condition which indicates which items are to be removed
    if (item.Key > 1)
    {
        removeList.Add(item.Key);
    }
}

أو إذا كنت تحاول ببساطة استرداد العناصر للحذف ، فاستخدم LINQ

var removeList = myDictionary.Where(pair => pair.Key > 1).Select(k => k.Key).ToList();

ثم فقط إزالتها من القائمة.

// remove from the main collection
foreach (var key in removeList)
{
    myDictionary.Remove(key);
}

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

يمكنك أولاً نسخ العناصر إلى قائمة أخرى ثم التكرار عبر هذه القائمة الجديدة من العناصر المراد تعديلها.

لا. يتم إلقاء invalidoperationexcpetion. أوافق على أن العناصر المذكورة بالفعل قد تكون قابلة للحذف نظرًا لوجود فهرس ثابت. لكن القضية هي ما يلي:

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

كما أشار الآخرون بالفعل ، لن ينجح. ومع ذلك ، نظرًا لأن المجموعة عبارة عن قائمة فرز ، يمكنك استخدام طريقة removeeat.

تحتوي هذه الطريقة على ملف تعريف ذاكرة أفضل قليلاً لأنه لا يتطلب أي عام على عكس الزيادة O (n) باستخدام قائمة منفصلة لتتبع عمليات الإزالة. سيكون لديه أيضًا ملف تعريف الأداء O (n^2) بدلاً من O (n^2 * log (n)). طريقة removeeat هي o (n) لأنه يجب أن تنفذ نسخة صفيف. تضيف طريقة إزالة عملية O (log (n)) للعثور على الفهرس قبل الاتصال داخليًا. كل هذا ربما لا يهمك ، لكن من المفيد أن تعرف في حال واجهت مواقف تتضمن الكثير من "N".

var myDictionary = new SortedList<decimal, string>();

// omitted code

int i = 0;
while (myDictionary.Count > 0 && i < myDictionary.Count)
{
  if (/* predicate to use for removal */)
  {
    myDictionary.RemoveAt(i);
  }
  else
  {
    i++;
  }
}

حل آخر :

            int counter= MyDictionary.Count;
            if (counter == 0)
                return;

            for (int i = 0;  i < counter;i++)
            {
                KeyValuePair<MyIdentifier, MyValue> key = (KeyValuePair<MyIdentifier, MyValue>)MyDictionary.ToArray()[i];
                MyIdentifier identifier = null;

                if (key.Key != null)
                    identifier = key.Key as MyIdentifier;

                if (identifier != null)
                    if (MyCondition)
                    {
                        MyDictionary.Remove(identifier);
                        counter--;
                    }
            }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top