【问题标题】:Iterating over a growing dictionary遍历不断增长的字典
【发布时间】:2013-09-03 04:15:03
【问题描述】:

我正在使用 C#,并且我有一本名为 intervalRecordsPerObject 的字典,类型为 Dictionary<string, List<TimeInterval>>。我需要遍历字典。问题是:每次我遍历字典时,可能会添加更多KeyValuePairs。随着字典的增长,我也需要不断迭代新条目。

首先,我这样做了:一个简单的foreach 循环,它给了我一个InvalidOperationException

Collection was modified; enumeration operation may not execute.

我知道如果字典在 foreach 循环之前用 ToList() 转换它时不断变化,我无法以这种方式迭代字典。

我知道我可以将键复制到一个临时数组,使用简单的for 循环和Count 遍历字典,并且每当向字典添加新条目时,也将相应的键添加到数组中。现在,问题是一个简单的数组不能动态增长,我事先不知道所需的大小可能是多少。

为了继续前进,我想我会这样做:

List<string> keyList = new List<string>(intervalRecordsPerObject.Count);
intervalRecordsPerObject.Keys.CopyTo(keyList.ToArray(), 0);

我也不能这样做。 keyList 当前为空,因此 keyList.toArray() 返回一个长度为 0 的数组,这给了我一个 ArgumentException

Destination array is not long enough to copy all the items in the collection. Check array index and length.

我被困住了!知道我还能尝试什么吗?感谢您的帮助。

加法1:

字典存储特定对象存在的时间间隔。键是对象的 ID。新条目可能会在每次迭代中添加(最坏的情况),或者甚至可能不会添加一次。是否添加条目由几个条件决定(对象是否与其他一些间隔重叠等)。这会触发 ID 和相应间隔列表的更改,然后将其作为新条目添加到字典中。

【问题讨论】:

  • 你能否提供更多关于迭代字典的目的的上下文,即你想做什么?以及多久添加一次新元素?
  • 如果你有两个线程访问同一个共享字典对象,你可能还有其他潜在的问题在等着你。您可能会受益于使用 ConcurrentDictionary msdn.microsoft.com/en-us/library/dd287191.aspx
  • 即使在您添加之后,我也不明白为什么您需要在添加新条目后遍历整个字典。为什么不直接处理已添加新条目的事实,可能是您存储在某处的一些正在运行的统计信息?再一次,需要更多的上下文。
  • 因为新添加的条目可以触发更多的新条目。这是在与其他一些区间比较的基础上完成的。一旦列表用尽,就不能再添加条目了。我需要的是最后出现在字典中的条目的完整列表。我希望它能清除一些灰尘!
  • 那么等到所有条目都添加完毕并遍历列表?说真的,很难提供有用的答案,因为您的问题描述是假设一个解决方案,而不是解释您要完成的实际事情,并且您的 cmets 没有添加足够的上下文。尝试将问题简化为最基本的形式。

标签: c# loops dictionary foreach invalidoperationexception


【解决方案1】:

类似这样的:

List<string> keys = dict.Keys.ToList();

for (int i = 0; i < keys.Count; i++)
{
    var key = keys[i];

    List<TimeInterval> value;

    if (!dict.TryGetValue(key, out value))
    {
        continue;
    }

    dict.Add("NewKey", yourValue);
    keys.Add("NewKey");
}

这里的诀窍是您通过 index 枚举List&lt;T&gt;!这样,即使你添加了新元素,for (...) 也会“捕捉”它们。

其他可能的解决方案,使用临时的Dictionary&lt;,&gt;

// The main dictionary
var dict = new Dictionary<string, List<TimeInterval>>();

// The temporary dictionary where new keys are added
var next = new Dictionary<string, List<TimeInterval>>();

// current will contain dict or the various instances of next
// (multiple new Dictionary<string, List<TimeInterval>>(); can 
// be created)
var current = dict;

while (true)
{
    foreach (var kv in current)
    {
        // if necessary
        List<TimeInterval> value = null;

        // We add items only to next, that will be processed
        // in the next while (true) cycle
        next.Add("NewKey", value);
    }

    if (next.Count == 0)
    {
        // Nothing was added in this cycle, we have finished
        break;
    }

    foreach (var kv in next)
    {
        dict.Add(kv.Key, kv.Value);
    }

    current = next;
    next = new Dictionary<string, List<TimeInterval>>();
}

【讨论】:

  • @DavidN Modified... 现在它将跳过不存在的键。
  • 永远不会从字典中删除键。此外,在键入 intervalRecordsPerObject.Keys. 时,我没有收到有关 Visual Studio 上 ToList() 方法的建议。我不知道为什么。这可以轻松解决我的问题。
  • @sleekFish 将using System.Linq; 添加到您的cs。
  • 谢谢!这真的很有帮助。
【解决方案2】:

您可以按位置而不是按内容访问Keys,并使用普通的For loop(允许添加/删除没有任何限制)。

for (int i = 0; i < dict.Keys.Count; i++)
{
    string curKey = dict.Keys.ElementAt(i);
    TimeInterval curVal = dict.Values.ElementAt(i);
    //TimeInterval curVal = dict[curKey];

   //Can add or remove entries
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 1970-01-01
    • 2020-09-01
    • 2015-08-07
    • 2013-04-16
    相关资源
    最近更新 更多