残念ながら、アイテムはスタックから "pop"によってのみ削除できます。スタックには「remove」メソッドなどはありませんが、スタック(はい、スタックが必要です!)があり、そこから要素を削除する必要があります。
これを行うトリックはありますか?
一番上にないアイテムを削除する必要がある場合は、スタック以外のものが必要です。
リストからスタックを独自に実装してみてください。次に、独自のプッシュ関数とポップ関数(リストで追加および削除)、および独自の特別なPopFromTheMiddle関数を実装します。
例えば
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);
}
}
別のコンテナの使用を検討してください。多分LinkedList。その後、使用できます
AddFirst AddLast RemoveLast RemoveFirst
スタックからポップ/プッシュのように使用できます
削除する
リストの中央からノードを削除するには
LinkedList を使用できます
リストベースの削除は、効率が低下する可能性があります。参照による削除では、リストベースのスタックはO(N) search and O(N) resizing。LinkedList search is O(N)であり、削除はO(1)です。インデックスによる削除の場合、LinkedListにはO(N)トラバーサルとO(1)削除が必要です、リストにはO(1)トラバーサル(インデックス化のため))とO(N)サイズ変更による削除が含まれます。
効率性に加えて、LinkedListの実装により、標準ライブラリに留まり、コードをより柔軟に開いて、記述を少なくすることができます。
これは、ポップ、プッシュ、および削除を処理できるはずです
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
}
おそらく拡張メソッドが機能しますが、実際には別のデータ構造が完全に必要であると思います。
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;
}
}
真のスタックでは、これは一方向にしか実行できません-
必要なものがなくなるまですべてのアイテムをポップしてから、適切な順序でスタックに戻します。
ただし、これはあまり効率的ではありません。
本当にどこからでも削除したい場合は、List、LinkedList、またはその他のコレクションから疑似スタックを構築することをお勧めします。これにより、これを簡単に実行できるようになります。
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);
私が厄介な状況で使用するトリックは、スタック内のアイテムに「非推奨」フラグを追加することです。アイテムを「削除」したい場合は、そのフラグを立てるだけです(そして、オブジェクトが取得したリソースをクリーンアップします)。次に、アイテムをPop()するときに、フラグが立っているかどうかを確認し、非推奨のアイテムが見つかるまでループで再度ポップします。
do
{
obj = mQueue.Pop();
} while (obj.deprecated);
独自のアイテム数を管理して、キューに残っている「実際の」アイテムの数を知ることができます。マルチスレッドソリューションで必要な場合は、明らかにロックを使用する必要があります。
フローが一定のキュー-アイテムがプッシュおよびポップされるキュー-この方法で処理する方がはるかに効率的であり、最も速く取得できます(アイテムを中央から削除するためにO(1)を支払う) )そして保持されるオブジェクトが小さい場合、メモリに関しては、アイテムが妥当なペースで流れるかどうかはほとんど関係ありません。
じゃあスタックじゃない?スタックはLAST in FIRST out
。カスタムのものを書くか、他のものを選択する必要があります。
Stack <>のコンストラクターは、IEnumerable <>をパラメーターとして受け取ります。したがって、次のことを実行できます。
myStack = new Stack<item>( myStack.Where(i => i != objectToRemove).Reverse() );
これは、多くの点で非パフォーマンスです。
リストを使用して、いくつかの拡張メソッドを追加しました。
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 ......私は前の2つの答えに同意しますが、自分のやり方をハッキングする場合は、必要な要素に到達するまですべての要素をポップして保存し、それらすべてを再度プッシュします
はい、醜い、パフォーマンスが悪い、おそらく奇妙なコードで、理由を説明する長いコメントが必要ですが、それは可能です...
私はこの質問に出くわしました。私のコードでは、独自の拡張メソッドを作成しました:
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());
}
}
}
そして、私はこのように私のメソッドを呼び出します:
var removedReportNumbers =
selectedReportNumbersInSession.Except(selectedReportNumbersList).ToList();
selectedReportNumbersInSession.Remove(removedReportNumbers);