2009-10-20 13 views
15

Zunächst einmal, nur zu gewähren, dass ich in der Tat die Funktionalität eines Queue<T> - FIFO, in der Regel nur brauchen Enqueue/Dequeue, etc. - und so würde ich lieber eine andere Antwort als "Was Sie wirklich wollen a List<T> "(Ich weiß über RemoveAt).Gibt es eine bessere Möglichkeit, eine Remove-Methode für eine Warteschlange zu implementieren?

Zum Beispiel sagen, ich habe eine Queue<DataPoint> dataToProcess von Datenpunkten, die in der Reihenfolge verarbeitet werden müssen, in der sie angekommen sind. Dann regelmäßig wäre es sinnvoll, einige Code wie diese haben:

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

Aber dann nehme an, für welchen Gründen auch immer, es wird festgestellt, dass ein bestimmter Datenpunkt, der mit der Warteschlange hinzugefügt wurde, sollte nicht verarbeitet werden. Dann wäre es ideal, wenn es eine Methode, ist analog zu:

dataToProcess.Remove(badPoint); 

Ich verstehe, dass es wirklich kein gangbarer Weg eine Remove Methode zu haben, die nicht in irgendeiner Form Aufzählung mit sich bringt; Da jedoch ein Queue<T> nicht wirklich lassen Sie nur in zu Fuß und einige Artikel zufällig entfernen, die einzige Lösung, die ich herausfinden konnte, war dies:

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

dies lächerlich ist? Es sicherlich sieht schlecht aus, aber ich kann nicht wirklich einen besseren Weg sehen, als eine benutzerdefinierte Klasse zu schreiben. Und selbst dann wäre der beste Weg, den ich denken könnte, um eine Methode zu implementieren, eine interne LinkedList<T> zu verwenden.

+0

PowerCollections (@codeplex) könnte nützlich sein für Sie –

Antwort

23

Ich denke, das Umschalten auf eine neue benutzerdefinierte Klasse, die eine LinkedList intern hatte, würde nur ein paar Minuten dauern und wäre viel leistungsfähiger als das, was Sie jetzt haben.

+0

Ich glaube, ich würde mit Ihnen eher zustimmen Deshalb habe ich diese Frage gestellt - weil ich mir keinen guten Weg vorstellen kann, dies mit einer "Queue " zu tun, aber ich dachte vielleicht jemand anders würde etwas sehen können, das mir gefehlt hat. –

+0

Sie können auch Ihre vorhandene Methode beschleunigen, indem Sie die Warteschlange bei der Warteschlange einreihen, anstatt Ihre Warteschlange in einer temporären Liste zu speichern. –

+0

@Jake: ziemlich clever - hatte nicht daran gedacht! Obwohl Ihre "LinkedList" -Implementierung sicherlich besser aussieht (und zu dem passt, was ich getan hätte ... ich denke, das ist immerhin die * Art, dies zu tun). –

9

Eine Alternative könnte sein, die Elemente einfach in der Warteschlange zu belassen und sie zu ignorieren, wenn Sie davon lesen. So etwas wie:

+3

Ich finde das ein sehr kluger Vorschlag. Ein Problem, das ich sehen kann, ist, dass, da das Element immer noch * in * der Warteschlange ist, es auch eine gefilterte Form von 'GetEnumerator' geben müsste, um die ignorierten Elemente während der Enumeration zu überspringen. –

1

Ich bin ein Anfänger, aber ich habe es geschafft, das gleiche (oder ein sehr ähnliches) Problem vor kurzem zu lösen. Ich hoffe es hilft.

Hier ist unsere Warteschlange:

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

Was passiert, wenn wir eine Kopie aller Warteschlange gestellt Elemente in eine Hashset (zB setzen:

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

so, wenn die Elemente Einreihen wir auch noch die gleichen Daten zum hashset.

und wenn sich herausstellt, wir brauchen nicht ein Element, entfernen wir es von diesem Hashset

pointsToProcess.Remove(element); 

so, wenn wir das nächste Element der Warteschlange ‚Verwendung‘ haben

wir prüfen, ob wir müssen mit ihnen umgehen wirklich (wenn es Mitglied der Hashset ist), ansonsten hat es ignoriert werden, und wir können es loswerden,

while (dataToProcess.Count > 0) { 


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


// processing data 


} 

else 
{ 

// error message and 

dataToProcess.Dequeue(); 

} 


} 
0

siehe c# Adding a Remove(int index) method to the .NET Queue class

Warteschlange ist die effizienteste Struktur für Warteschlangen, das Implementieren einer Warteschlange auf einer Listendatenstruktur ist nicht effizient.

Obwohl es keine integrierte Möglichkeit ist, können Sie keine Liste Struktur oder eine andere Struktur verwendet werden soll, ist IFF Entfernen nicht eine häufige Operation.

Wenn Sie normalerweise in die Warteschlange stellen und die Warteschlange entfernen, aber nur gelegentlich entfernen, dann sollten Sie in der Lage sein, eine Wiederherstellung der Warteschlange zu leisten, wenn entfernt wird.

siehe den Link für zwei einfache Erweiterungsmethoden

public static void Remove<T>(this Queue<T> queue, T itemToRemove) where T : class

public static void RemoveAt<T>(this Queue<T> queue, int itemIndex) where T : class

-2
var first = Q.Dequeue(); 
if (first.Id.Equals(deleteId)) return; 
Q.Enqueue(first); 

while (Q.Peek() != first) 
{ 
    var r = Q.Dequeue(); 
    if(!r.Id.Equals(deleteId)) Q.Enqueue(r); 
} 
Verwandte Themen