3

我的问题是枚举器从 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);
}
4

6 回答 6

8

这将引发异常 - 您无法在迭代集合时对其进行修改。

如果你稍微考虑一下,你就会明白为什么。如果允许从集合中添加或删除,您将不再迭代同一个集合 - 您有太多(添加)或没有足够的项目(删除)。

于 2010-04-23T12:38:04.893 回答
4

如前所述,您想要做的事情是不可能的。但是,另一种解决方案是简单地维护一个标记为删除的项目列表,然后删除这些后记。我也会选择一个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);
}
于 2010-04-23T12:54:10.447 回答
2

No. An InvalidOperationExcpetion is thrown. I agree that already enumerated items might be deletable since there is a fixed index. However the issue is the following:

The implementation of SortedList is not clever enough to figure out that the removal will have no affect on the further execution of the enumerable. And to keep it simple and performing well, it shouldn't.

于 2010-04-23T12:45:01.513 回答
2

一般不支持迭代期间对列表的操作。预期的行为是抛出异常,但即使集合未能做到这一点,您也不能依赖它正常工作。

您可以先将元素复制到另一个列表中,然后遍历这个要修改的新项目列表。

于 2010-04-23T12:38:28.677 回答
2

正如其他人已经指出的那样,它不会起作用。但是,由于该集合是一个 SortedList,您可以使用 RemoveAt 方法。

此方法具有稍微更好的内存配置文件,因为它不需要开销,而不是使用单独的列表来跟踪删除的 O(n) 增加。与 O(n^2 * log(n)) 相比,它还具有 O(n^2) 性能配置文件。RemoveAt 方法是 O(n),因为它必须执行数组复制。Remove 方法在内部调用 RemoveAt 之前添加了一个 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++;
  }
}
于 2010-04-23T14:23:27.843 回答
0

An other solution :

            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--;
                    }
            }
于 2013-04-17T04:39:50.500 回答