Uno de los desafíos de codificación más interesantes que me dieron para una entrevista fue crear una cola funcional. El requisito era que cada llamada a la cola creara una nueva cola que contuviera la cola anterior y el nuevo elemento en la cola. Dequeue también devolvería una nueva cola y el elemento retirado como un parámetro fuera.
Crear un IEnumerator a partir de esta implementación no sería destructivo. Y déjenme decirles que implementar una cola funcional que funciona bien es mucho más difícil que implementar una pila funcional eficiente (la pila Push / Pop funciona en la cola, porque una cola en cola funciona en la cola, la cola funciona en la cabeza).
Mi punto es ... es trivial crear un enumerador de pila no destructivo mediante la implementación de su propio mecanismo de puntero (StackNode <T>) y el uso de la semántica funcional en el enumerador.
public class Stack<T> implements IEnumerator<T>
{
private class StackNode<T>
{
private readonly T _data;
private readonly StackNode<T> _next;
public StackNode(T data, StackNode<T> next)
{
_data=data;
_next=next;
}
public <T> Data{get {return _data;}}
public StackNode<T> Next{get {return _Next;}}
}
private StackNode<T> _head;
public void Push(T item)
{
_head =new StackNode<T>(item,_head);
}
public T Pop()
{
//Add in handling for a null head (i.e. fresh stack)
var temp=_head.Data;
_head=_head.Next;
return temp;
}
///Here's the fun part
public IEnumerator<T> GetEnumerator()
{
//make a copy.
var current=_head;
while(current!=null)
{
yield return current.Data;
current=_head.Next;
}
}
}
Algunas cosas a tener en cuenta. Una llamada para empujar o hacer estallar antes de la instrucción current = _head; completar le daría una pila diferente para la enumeración que si no hubiera subprocesamiento múltiple (es posible que desee utilizar un ReaderWriterLock para protegerse contra esto). Hice que los campos en StackNode fueran de solo lectura pero, por supuesto, si T es un objeto mutable, puede cambiar sus valores. Si fuera a crear un constructor de pila que tomara un StackNode como parámetro (y estableciera la cabeza en el nodo pasado). Dos pilas construidas de esta manera no se impactarán entre sí (con la excepción de una T mutable como mencioné). Puedes empujar y hacer estallar todo lo que quieras en una pila, la otra no cambiará.
Y que mi amigo es cómo haces una enumeración no destructiva de una Pila.