在迭代期间从 SortedList 中删除是否安全

发布于 2024-08-29 15:04:49 字数 298 浏览 5 评论 0原文

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

My question is is it safe for enumerator to remove item from 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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

却一份温柔 2024-09-05 15:04:49

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

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

This will throw an exception - you cannot modify a collection while iterating over it.

If you think about it a little, you will understand why. If adding or removing from the collection was allowed, you would no longer be iterating over the same collection - you either have too many (adding) or not enough items (removing).

剑心龙吟 2024-09-05 15:04:49

正如已经说过的,你想要做的事情是不可能的。然而,另一种解决方案是简单地维护一个标记为删除的项目列表,然后删除这些后记。我还会选择 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);
}

As already stated what you are looking to do is not possible. However, an alternative solution would be to simply maintain a list of items marked for deletion and then remove these afterwords. I would also opt for a foreach rather than a while loop, less code e.g.

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);
    }
}

Or if you are simply trying to retrieve items for deletion, use LINQ

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

Then just remove them from the list.

// remove from the main collection
foreach (var key in removeList)
{
    myDictionary.Remove(key);
}
狠疯拽 2024-09-05 15:04:49

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

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

Operations on the list during iterations are not supported in general. The expected behaviour is to throw an exception, but even if a collection fails to do this you must not rely on this working correctly.

You can first copy the elements into another list and then iterate over this new list of items to be modified.

小女人ら 2024-09-05 15:04:49

不会。会引发 InvalidOperationExcpetion。我同意已经枚举的项目可能是可删除的,因为有固定的索引。但问题如下:

SortedList 的实现不够聪明,无法弄清楚删除不会影响可枚举的进一步执行。为了保持简单和性能良好,它不应该。

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.

五里雾 2024-09-05 15:04:49

正如其他人已经指出的那样,这是行不通的。但是,由于集合是 SortedList,因此您可以使用 RemoveAt 方法。

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

As others have already pointed out it will not work. However, since the collection is a SortedList you can use the RemoveAt method.

This method has a slightly better memory profile since it requires no overhead as opposed to a O(n) increase using a separate list to keep track of removals. It would also have a O(n^2) performance profile as opposed to O(n^2 * log(n)). The RemoveAt method is O(n) since it must perform an array copy. The Remove method adds a O(log(n)) operation to find the index before internally calling RemoveAt. All of this is probably of no concern to you, but it is useful know in case you run into situations involving a lot of '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++;
  }
}
赠佳期 2024-09-05 15:04:49

另一种解决方案:

            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--;
                    }
            }

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--;
                    }
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文