Actualizar:
Para personas interesadas en el nivel de anidación (profundidad). Una de las cosas buenas de la implementación explícita de la pila de enumeradores es que en cualquier momento (y en particular cuando se obtiene el elemento) stack.Count
representa la profundidad de procesamiento actual. Entonces, teniendo esto en cuenta y utilizando las tuplas de valor de C # 7.0, podemos simplemente cambiar la declaración del método de la siguiente manera:
public static IEnumerable<(T Item, int Level)> ExpandWithLevel<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
y yield
declaración:
yield return (item, stack.Count);
Entonces podemos implementar el método original aplicando simple Select
en lo anterior:
public static IEnumerable<T> Expand<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector) =>
source.ExpandWithLevel(elementSelector).Select(e => e.Item);
Original:
Sorprendentemente, nadie (ni siquiera Eric) mostró el puerto iterativo "natural" de una DFT recursiva de reserva, así que aquí está:
public static IEnumerable<T> Expand<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}