سؤال

I am working with C# and I have a dictionary called intervalRecordsPerObject of type Dictionary<string, List<TimeInterval>>. I need to iterate through the dictionary. The problem is: everytime I iterate through the dictionary, more KeyValuePairs may get added to it. As the dictionary grows, I need to keep iterating over the new entries too.

Firstly, I did this: A simple foreach loop that gave me an InvalidOperationException saying

Collection was modified; enumeration operation may not execute.

I know I cannot iterate over the Dictionary this way if it keeps changing as C# converts it with ToList() before foreach loop.

I know I can copy the keys to a temporary array, iterate over the dictionary using simple for loop and Count and whenever a new entry is added to the dictionary, add the corresponding key to the array too. Now, the problem is a simple array cannot grow dynamically and I don't know beforehand what the required size could be.

To move ahead, I thought I'd do this:

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

I cannot do this either. keyList is currently empty and therefore keyList.toArray() returns an array of length 0 which gives me an ArgumentException saying

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

I am stuck! Any idea what more can I try? Thanks for any help.

Addition 1:

The dictionary stores the time intervals for which a particular object is present. Key is the ID of the object. New entries may get added in every iteration (worst case) or may not get added even once. Whether or not entries are added is decided by a few conditions (whether the object overlaps with some other intervals, etc.). This triggers a change in the ID and the corresponding interval list which is then added as a new entry to the dictionary.

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

المحلول

Something like this:

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

The trick here is that you enumerate the List<T> by index! In this way, even if you add new elements, the for (...) will "catch" them.

Other possible solution, by using a temporary Dictionary<,>:

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

نصائح أخرى

You can access the Keys by positions rather than by content and use a normal For loop (allowing additions/removals without any restriction).

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
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top