Una delle sfide di codifica più interessanti che mi sono state date per un'intervista era creare una coda funzionale. Il requisito era che ogni chiamata ad accodamento creava una nuova coda che conteneva la vecchia coda e il nuovo elemento alla coda. Dequeue restituirebbe anche una nuova coda e l'elemento in coda deselezionata come un parametro out.
La creazione di un IEnumerator da questa implementazione sarebbe non distruttiva. E lasciatemi dire che implementare una coda funzionale che si comporta bene è molto più difficile dell'implementazione di uno stack funzionale performante (stack Push / Pop funzionano entrambi sulla coda, perché una coda accoda sulla coda, deseleziona i lavori sulla testa).
Il mio punto è ... è banale creare un Enumeratore di Stack non distruttivo implementando il proprio meccanismo di Puntatore (StackNode & Tt; T >) e utilizzando la semantica funzionale nell'Enumeratore.
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;
}
}
}
Alcune cose da notare. Una chiamata a push o pop prima dell'istruzione current = _head; Completi ti darebbe uno stack diverso per l'enumerazione rispetto a se non ci fosse il multithreading (potresti voler usare un ReaderWriterLock per salvaguardare questo). Ho reso i campi in StackNode in sola lettura, ma ovviamente se T è un oggetto mutabile, puoi cambiarne i valori. Se si dovesse creare un costruttore Stack che ha preso un StackNode come parametro (e impostare la testa su quello passato nel nodo). Due pile costruite in questo modo non si influenzeranno a vicenda (ad eccezione di un T mutabile come ho detto). Puoi spingere e far saltare tutto ciò che vuoi in una pila, l'altra non cambierà.
E che mio amico è come fai l'enumerazione non distruttiva di uno Stack.