I would like to use the generic queue class as described in the .NET framework (3.5) but I will need a Remove(int index) method to remove items from the queue. Can I achieve
Combining both casperOne's and David Anderson's suggestions to the next level. The following class inherits from List and hides the methods that would be detrimental to the FIFO concept while adding the three Queue methods (Equeue, Dequeu, Peek).
public class ListQueue<T> : List<T>
{
new public void Add(T item) { throw new NotSupportedException(); }
new public void AddRange(IEnumerable<T> collection) { throw new NotSupportedException(); }
new public void Insert(int index, T item) { throw new NotSupportedException(); }
new public void InsertRange(int index, IEnumerable<T> collection) { throw new NotSupportedException(); }
new public void Reverse() { throw new NotSupportedException(); }
new public void Reverse(int index, int count) { throw new NotSupportedException(); }
new public void Sort() { throw new NotSupportedException(); }
new public void Sort(Comparison<T> comparison) { throw new NotSupportedException(); }
new public void Sort(IComparer<T> comparer) { throw new NotSupportedException(); }
new public void Sort(int index, int count, IComparer<T> comparer) { throw new NotSupportedException(); }
public void Enqueue(T item)
{
base.Add(item);
}
public T Dequeue()
{
var t = base[0];
base.RemoveAt(0);
return t;
}
public T Peek()
{
return base[0];
}
}
Test code:
class Program
{
static void Main(string[] args)
{
ListQueue<string> queue = new ListQueue<string>();
Console.WriteLine("Item count in ListQueue: {0}", queue.Count);
Console.WriteLine();
for (int i = 1; i <= 10; i++)
{
var text = String.Format("Test{0}", i);
queue.Enqueue(text);
Console.WriteLine("Just enqueued: {0}", text);
}
Console.WriteLine();
Console.WriteLine("Item count in ListQueue: {0}", queue.Count);
Console.WriteLine();
var peekText = queue.Peek();
Console.WriteLine("Just peeked at: {0}", peekText);
Console.WriteLine();
var textToRemove = "Test5";
queue.Remove(textToRemove);
Console.WriteLine("Just removed: {0}", textToRemove);
Console.WriteLine();
var queueCount = queue.Count;
for (int i = 0; i < queueCount; i++)
{
var text = queue.Dequeue();
Console.WriteLine("Just dequeued: {0}", text);
}
Console.WriteLine();
Console.WriteLine("Item count in ListQueue: {0}", queue.Count);
Console.WriteLine();
Console.WriteLine("Now try to ADD an item...should cause an exception.");
queue.Add("shouldFail");
}
}
Here's how you remove a specific item from the queue with one line of Linq (it's recreating the queue, BUT for the lack of a better method...)
//replace "<string>" with your actual underlying type
myqueue = new Queue<string>(myqueue.Where(s => s != itemToBeRemoved));
I know it's not removing by index, but still, someone might find this useful (this question ranks in Google for "remove specific item from a c# queue" so I decided to add this answer, sorry)
David Anderson's solution is probably the best but has some overhead. Are you using custom objects in the queue? if so, add a boolean like cancel
Check with your workers that process the queue if that boolean is set and then skip it.
It's a pretty late answer but I write it for future readers
List<T>
is exactly what you need but it has a big disadvantage when compared to Queue<T>
: it's implemented with an array then Dequeue()
is pretty expansive (in terms of time) because all items must be shifted one step back with Array.Copy
. Even Queue<T>
uses an array but together with two indices (for head and tail).
In your case you also need Remove
/RemoveAt
and its performance won't be good (for the same reason: if you're not removing from list tail then another array must be allocated and items copied).
A better data structure to have quick Dequeue
/Remove
time is a linked list (you'll sacrifice - a little bit - performance for Enqueue
but assuming your queue has an equal number of Enqueue
/Dequeue
operations you'll have a great gain in performance, especially when its size will grow).
Let's see a simple skeleton for its implementation (I'll skip implementation for IEnumerable<T>
, IList<T>
and other helper methods).
class LinkedQueue<T>
{
public int Count
{
get { return _items.Count; }
}
public void Enqueue(T item)
{
_items.AddLast(item);
}
public T Dequeue()
{
if (_items.First == null)
throw new InvalidOperationException("...");
var item = _items.First.Value;
_items.RemoveFirst();
return item;
}
public void Remove(T item)
{
_items.Remove(item);
}
public void RemoveAt(int index)
{
Remove(_items.Skip(index).First());
}
private LinkedList<T> _items = new LinkedList<T>();
}
For a quick comparison:
Queue List LinkedList Enqueue O(1)/O(n)* O(1)/O(n)* O(1) Dequeue O(1) O(n) O(1) Remove n/a O(n) O(n)
* O(1) is typical case but sometimes it'll be O(n) (when internal array need to be resized).
Of course you'll pay something for what you gain: memory usage is bigger (especially for small T
overhead will be great). Right implementation (List<T>
vs LinkedList<T>
) must be chosen carefully according to your usage scenario, you may also convert that code to use a single linked list to reduce 50% of memory overhead.
Someone will probably develop a better solution, but from what I see you will need to return a new Queue object in your Remove method. You'll want to check if the index is out of bounds and I may have got the ordering of the items being added wrong, but here's a quick and dirty example that could be made into an extension quite easily.
public class MyQueue<T> : Queue<T> {
public MyQueue()
: base() {
// Default constructor
}
public MyQueue(Int32 capacity)
: base(capacity) {
// Default constructor
}
/// <summary>
/// Removes the item at the specified index and returns a new Queue
/// </summary>
public MyQueue<T> RemoveAt(Int32 index) {
MyQueue<T> retVal = new MyQueue<T>(Count - 1);
for (Int32 i = 0; i < this.Count - 1; i++) {
if (i != index) {
retVal.Enqueue(this.ElementAt(i));
}
}
return retVal;
}
}
If the Queue is being used to preserve the order of the items in the collection, and if you will not have duplicate items, then a SortedSet might be what you are looking for. The SortedSet
acts much like a List<T>
, but stays ordered. Great for things like drop down selections.