Есть ли что-то вроде расширяемой очереди в C #? - PullRequest
2 голосов
/ 04 декабря 2010

У меня есть набор идентификаторов, над которыми я выполняю некоторые операции:

Queue<string> queue = new Queue<string>();
queue.Enqueue("1");
queue.Enqueue("2");
...
queue.Enqueue("10");

foreach (string id in queue)
{
    DoSomeWork(id);
}

static void DoSomeWork(string id)
{
   // Do some work and oooo there are new ids which should also be processed :)
   foreach(string newID in newIDs)
   {
       if(!queue.Contains(newID)) queue.Enqueue(newID);
   }
}

Можно ли добавить некоторые новые элементы в queue в DoSomeWork(), которые также будут обрабатываться в основном цикле foreach-loop

Ответы [ 3 ]

3 голосов
/ 04 декабря 2010

Что вы делаете, так это используете итератор поверх изменяющейся коллекции. Это плохая практика, поскольку некоторые коллекции при этом выдают исключение (например, коллекция не должна изменяться при перечислении).

Используйте следующий подход, который также использует новые предметы:

while (queue.Count > 0)
{
    DoSomeWork(queue.Dequeue());
}
1 голос
/ 04 декабря 2010

Используйте Dequeue вместо цикла foreach.Большинство перечислителей становятся недействительными при каждом изменении основного контейнера.И En- / Dequeue являются естественными операциями в очереди.В противном случае вы можете использовать List<T> или HashSet<T>

while(queue.Count>0)
{
  var value=queue.Dequeue();
  ...
}

Чтобы проверить, был ли предмет уже обработан, HashSet<T> является быстрым решением.В этих случаях я обычно использую комбинацию HashSet и Queue.Преимущество этого решения состоит в том, что это O (n), потому что проверка и добавление к HashSet - это O (1).Ваш исходный код был O (n ^ 2), поскольку Contains на Queue означает O (n).

Queue<string> queue=new Queue<string>();
HashSet<string> allItems=new HashSet<string>();

void Add(string item)
{
  if(allItems.Add(item))
    queue.Enqueue(item);
}

void DoWork()
{
    while(queue.Count>0)
    {
      var value=queue.Dequeue();
      ...
    }  
}
0 голосов
/ 04 декабря 2010

Обычно итерации цикла добавляют больше работы; просто передайте очередь в метод в качестве аргумента и добавление к ней должно работать нормально.

Проблема в том, что вы должны использовать Dequeue:

while(queue.Count>0) {
    DoSomeWork(queue.Dequeue());
}
...