views:

70

answers:

2

First of all, just grant that I do in fact want the functionality of a Queue<T> -- FIFO, generally only need Enqueue/Dequeue, etc. -- and so I'd prefer an answer other than "What you really want is a List<T>" (I know about RemoveAt).

For example, say I have a Queue<DataPoint> dataToProcess of data points that need to be processed in the order in which they arrived. Then periodically it would make sense to have some code like this:

while (dataToProcess.Count > 0) {
    DataPoint pointToProcess = dataToProcess.Dequeue();
    ProcessDataPoint(pointToProcess);
}

But then suppose, for whatever reason, it's discovered that a particular data point which has been added to the queue should not be processed. Then it would be ideal if there were a method analogous to:

dataToProcess.Remove(badPoint);

I understand that there's really no feasible way to have a Remove method that does not involve some form of enumeration; however, since a Queue<T> doesn't really let you just walk in and remove some item randomly, the only solution I could figure out was this:

bool Remove(T item) {
    bool itemFound = false;

    // set up a temporary queue to take items out
    // one by one
    Queue<T> receivingQueue = new Queue<T>();

    // move all non-matching items out into the
    // temporary queue
    while (this.Count > 0) {
        T next = this.Dequeue();
        if (next.Equals(item)) {
            itemFound = true;
        } else {
            receivingQueue.Enqueue(next);
        }
    }

    // return the items back into the original
    // queue
    while (receivingQueue.Count > 0) {
        this.Enqueue(receivingQueue.Dequeue());
    }

    return itemFound;
}

Is this ridiculous? It certainly looks bad, but I can't really see a better way, other than writing a custom class. And even then, the best way I could think to implement a Remove method would be to use a LinkedList<T> internally.

+1  A: 

I think switching over to a new custom class that had a LinkedList internally would only take you a few minutes and would be much more performant than what you have now.

public class SpecialQueue<T>
{
 LinkedList<T> list = new LinkedList<T>();

 public void Enqueue(T t)
 {
  list.AddLast(t);
 }

 public T Dequeue()
 {
  var result = list.First.Value;
  list.RemoveFirst();
  return result;
 }

 public T Peek()
 {
  return list.First.Value;
 }

 public bool Remove(T t)
 {
  return list.Remove(t);
 }
}
Jake Pearson
I guess I would tend to agree with you, which is why I asked this question--because I can't think of a good way to go about doing this with a `Queue<T>`, but I thought maybe someone else would be able to see something I was missing.
Dan Tao
Also, you can speed up your existing method by enqueueing as you dequeue instead of saving your queue to a temporary list.
Jake Pearson
@Jake: quite clever -- hadn't thought of that! Though your `LinkedList` implementation certainly does seem better (and matches what I would have done... I guess that's pretty much *the* way to do it, after all).
Dan Tao
+2  A: 

An alternative could be to just leave the items in the queue, and ignore them when you are reading from it. Something like:

T DequeueFiltered(HashSet<T> ignored) {
   T item;
   while (ignored.Contains(item = Dequeue())) {
      ignored.Remove(item);
   }
   return item;
}
Guffa
I find this a very smart suggestion. One issue I can see is that, since the item is still *in* the queue, there'd have to be a filtered form of `GetEnumerator` as well, to skip the ignored items during enumeration.
Dan Tao