Это сложно, поскольку «последний элемент» не является точкой остановки Маркова: вы не можете сказать, что добрались до последнего элемента, пока не попробуете получить следующий. Это выполнимо, но только если вы не против постоянно быть «одним элементом позади». Это в основном то, что делает ваша текущая реализация, и выглядит хорошо, хотя я бы, наверное, написал это немного по-другому.
Альтернативным подходом было бы использовать foreach
, всегда получая ранее возвращенное значение, если вы не были на первой итерации:
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
T previous = default(T);
bool first = true;
foreach (T element in source)
{
if (!first)
{
yield return previous;
}
previous = element;
first = false;
}
}
Еще один вариант, ближе к вашему коду:
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
using (IEnumerator<T> iterator = source.GetEnumerator())
{
if(!iterator.MoveNext())
{
yield break;
}
T previous = iterator.Current;
while (iterator.MoveNext())
{
yield return previous;
previous = iterator.Current;
}
}
}
Это позволяет избежать столь же глубокого вложения (выполняя ранний выход, если последовательность пуста), и вместо while(true)
используется "реальное" условие while