Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way to implement a Remove method for a Queue?

Tags:

c#

.net

queue

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.

like image 703
Dan Tao Avatar asked Oct 20 '09 12:10

Dan Tao


People also ask

Which queue method should be used to remove an element from the collection?

Queue remove() method in Java The remove() method of Queue Interface returns and removes the element at the front of the container. It deletes the head of the container. The method throws an NoSuchElementException when the Queue is empty.

Which implementation of queue is best?

It's better to use ArrayDeque instead of LinkedList when implementing Stack and Queue in Java. ArrayDeque is likely to be faster than Stack interface (while Stack is thread-safe) when used as a stack, and faster than LinkedList when used as a queue.

How do I remove a specific value from a queue in Java?

You could use the method: remove(Object o) Removes the first occurrence of the specified element from this list, if it is present. If this list does not contain the element, it is unchanged.


3 Answers

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

            public int Count { get { return list.Count; } }
}
like image 186
Jake Pearson Avatar answered Oct 12 '22 11:10

Jake Pearson


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;
}
like image 23
Guffa Avatar answered Oct 12 '22 11:10

Guffa


I am a beginner however I managed to solve the same (or a very similar) issue recently. I hope it helps.

Here is our queue:

Queue<T> dataToProcess = new Queue<T>();

What if we put a copy of all enqueued items into a hashset (e.g.:

HashSet<T> pointsToProcess = new HashSet<T>(); 

so when enqueueing the elements we also add the same data to the hashset.

and When it turns out we don't need an element, we remove it from that hashset

pointsToProcess.Remove(element);

so when we have to 'use' the next element of the queue,

we examine whether we really need to deal with it (if it's member of the hashset) otherwise it has to be ignored and we can get rid of it,

while (dataToProcess.Count > 0) {


if  pointsToProcess.Contains(dataToProcess.Peek())
{


// processing data


}

else
{

// error message and

dataToProcess.Dequeue();

}


}
like image 36
vampierre Avatar answered Oct 12 '22 10:10

vampierre