Malheureusement, un élément ne peut être retiré de la pile que par "pop". La pile n'a pas de méthode "remove" ou quelque chose de similaire, mais j'ai une pile (oui, j'ai besoin d'une pile!) À partir de laquelle j'ai besoin de supprimer certains éléments entre.
Y a-t-il un truc pour faire ça?
Si vous devez supprimer des éléments qui ne sont pas au sommet, vous avez besoin d'autre chose que d'une pile.
Essayez de créer votre propre implémentation d'une pile à partir d'une liste. Ensuite, vous devez implémenter vos propres fonctions Push et Pop (ajouter et supprimer de la liste) et votre propre fonction spéciale PopFromTheMiddle.
Par exemple
public class ItsAlmostAStack<T>
{
private List<T> items = new List<T>();
public void Push(T item)
{
items.Add(item);
}
public T Pop()
{
if (items.Count > 0)
{
T temp = items[items.Count - 1];
items.RemoveAt(items.Count - 1);
return temp;
}
else
return default(T);
}
public void Remove(int itemAtPosition)
{
items.RemoveAt(itemAtPosition);
}
}
Pensez à utiliser un conteneur différent. Peut-être une LinkedList ..__ Ensuite, vous pouvez utiliser
AddFirst AddLast RemoveLast RemoveFirst
comme pop/push de la pile et vous pouvez utiliser
Retirer
supprimer n'importe quel nœud du milieu de la liste
Vous pouvez utiliser un LinkedList
La suppression basée sur les listes sera probablement moins efficace . Dans la suppression par référence, les piles basées sur la liste auront la recherche O(N) et le redimensionnement O(N). La recherche LinkedList est O(N) et la suppression est O (1). Pour la suppression par index, LinkedList doit avoir O(N) traversal et O(1) suppression, tandis que List aura O(1) traversal (car il s'agit d'une indexation) et suppression de O(N) en raison du redimensionnement.
Outre l'efficacité, une implémentation de LinkedList vous maintiendra dans la bibliothèque standard, ouvrant votre code à plus de flexibilité et vous permettant d'écrire moins.
Cela devrait être capable de gérer Pop, Push et Remove
public class FIFOStack<T> : LinkedList<T>
{
public T Pop()
{
T first = First();
RemoveFirst();
return first;
}
public void Push(T object)
{
AddFirst(object);
}
//Remove(T object) implemented in LinkedList
}
Peut-être une méthode d'extension fonctionnerait-elle, bien que je soupçonne qu'une structure de données totalement différente est vraiment nécessaire.
public static T Remove<T>( this Stack<T> stack, T element )
{
T obj = stack.Pop();
if (obj.Equals(element))
{
return obj;
}
else
{
T toReturn = stack.Remove( element );
stack.Push(obj);
return toReturn;
}
}
Dans une vraie pile, cela ne peut être fait que dans un sens -
Pop tous les éléments jusqu'à ce que vous supprimiez celui que vous voulez, puis repoussez-les sur la pile dans l'ordre approprié.
Ce n'est pas très efficace, cependant.
Si vous souhaitez vraiment supprimer de n’importe quel emplacement, je vous recommande de créer une pseudo-pile à partir d’une liste, d’une liste liée ou d’une autre collection. Cela vous donnerait le contrôle pour le faire facilement.
Stack temp = new Stack();
object x, y;
While ((x = myStack.Pop()) != ObjectImSearchingFor)
temp.Push(x);
object found = x;
While ((y = temp.Pop()) != null)
myStack.Push(y);
Une astuce que j’utilise dans les situations délicates consiste à ajouter un indicateur «obsolète» aux éléments de la pile . object) . Ensuite, lorsque Pop () ing éléments, je vérifie simplement si l'indicateur est levé, et saute à nouveau dans une boucle jusqu'à ce qu'un élément non obsolète soit trouvé.
do
{
obj = mQueue.Pop();
} while (obj.deprecated);
Vous pouvez gérer votre propre nombre d'éléments pour savoir combien d'éléments "réels" sont encore dans la file d'attente. De toute évidence, le verrouillage doit être utilisé si cela est nécessaire pour une solution multithread.
J'ai trouvé que, pour les files d'attente traversées par un flux constant (éléments poussés et sautés), il est bien plus efficace de le gérer de cette façon, c'est le plus rapide possible (paiement O(1) pour le retrait d'un élément du milieu. ) et au niveau mémoire, si l’objet retenu est petit, il n’est généralement pas pertinent de le faire si les objets suivent un rythme raisonnable.
Alors ce n'est pas une pile non? La pile est LAST in FIRST out
. Vous devrez écrire un personnalisé ou choisir quelque chose.
Le constructeur d'une pile <> prend IEnumerable <> en tant que paramètre. Il serait donc possible d'effectuer les tâches suivantes:
myStack = new Stack<item>( myStack.Where(i => i != objectToRemove).Reverse() );
Ceci est non performant à plusieurs égards.
J'ai utilisé une liste et ajouté des méthodes d'extension, par exemple,
public static IThing Pop(this List<IThing> list)
{
if (list == null || list.Count == 0) return default(IThing);
// get last item to return
var thing = list[list.Count - 1];
// remove last item
list.RemoveAt(list.Count-1);
return thing;
}
public static IThing Peek(this List<IThing> list)
{
if (list == null || list.Count == 0) return default(IThing);
// get last item to return
return list[list.Count - 1];
}
public static void Remove(this List<IThing> list, IThing thing)
{
if (list == null || list.Count == 0) return;
if (!list.Contains(thing)) return;
list.Remove(thing); // only removes the first it finds
}
public static void Insert(this List<IThing> list, int index, IThing thing)
{
if (list == null || index > list.Count || index < 0) return;
list.Insert(index, thing);
}
hmmmm ...... Je suis d'accord avec les deux réponses précédentes, mais si vous cherchez à pirater votre chemin, sautez simplement et sauvegardez tous les éléments jusqu'à ce que vous obteniez celui que vous voulez, et ré-appuyez dessus
Oui, c'est un code moche, peu performant, probablement bizarre qui nécessitera un long commentaire expliquant pourquoi, mais vous pouvez le faire ....
Je suis tombé sur cette question. Dans mon code, j'ai créé ma propre méthode d'extension:
public static class StackExtensions
{
public static void Remove<T>(this Stack<T> myStack, ICollection<T> elementsToRemove)
{
var reversedStack = new Stack<T>();
while(myStack.Count > 0)
{
var topItem = myStack.Pop();
if (!elementsToRemove.Contains(topItem))
{
reversedStack.Push(topItem);
}
}
while(reversedStack.Count > 0)
{
myStack.Push(reversedStack.Pop());
}
}
}
Et j'appelle ma méthode comme ceci:
var removedReportNumbers =
selectedReportNumbersInSession.Except(selectedReportNumbersList).ToList();
selectedReportNumbersInSession.Remove(removedReportNumbers);