Бывают случаи, когда полезно проверить non-repeatableIEnumerable
, чтобы узнать, пусто или нет. LINQ's Any
не подходит для этого, так как он потребляет первый элемент последовательности, например.Безопасная проверка неповторяющихся IEnumerables для пустоты
if(input.Any())
{
foreach(int i in input)
{
// Will miss the first element for non-repeatable sequences!
}
}
(Примечание: Я знаю, что нет необходимости делать проверку в данном случае - это просто пример реального мира пример выполнения Zip
против правой IEnumerable
, который потенциально может быть! . пустой Если он пуст, я хочу, чтобы результат левая IEnumerable
как есть)
Я придумал потенциальное решение, которое выглядит следующим образом:.
private static IEnumerable<T> NullifyIfEmptyHelper<T>(IEnumerator<T> e)
{
using(e)
{
do
{
yield return e.Current;
} while (e.MoveNext());
}
}
public static IEnumerable<T> NullifyIfEmpty<T>(this IEnumerable<T> source)
{
IEnumerator<T> e = source.GetEnumerator();
if(e.MoveNext())
{
return NullifyIfEmptyHelper(e);
}
else
{
e.Dispose();
return null;
}
}
Это может тогда можно использовать следующим образом:
input = input.NullifyIfEmpty();
if(input != null)
{
foreach(int i in input)
{
// Will include the first element.
}
}
У меня есть два вопроса по этому поводу:
1) Является ли это разумно, что нужно сделать? Возможно, это проблематично с точки зрения производительности? (Думаю, не стоит, но стоит спросить.)
2) Есть ли лучший способ достичь той же конечной цели?
РЕДАКТИРОВАТЬ # 1:
Вот пример не-повторяемого IEnumerable
, чтобы уточнить:
private static IEnumerable<int> ReadNumbers()
{
for(;;)
{
int i;
if (int.TryParse(Console.ReadLine(), out i) && i != -1)
{
yield return i;
}
else
{
yield break;
}
}
}
В основном, вещи, которые приходят из пользовательского ввода или поток, и т.д.
EDIT # 2:
Мне нужно уточнить, что я ищу решение что сохраняет ленивый характер IEnumerable
- преобразование его в список или массив может быть ответом при определенных обстоятельствах, но это не то, что я здесь. (Реальная причина в том, что количество элементов в IEnumerable
может быть огромным в моем случае, и важно не хранить их все в памяти сразу.)
Это умный подход. Мне будет интересно услышать отзывы других, но для меня это выглядит довольно элегантным способом решения вашей проблемы. –
Не уверен, что вы подразумеваете под «non-repeatable ienumerable». У вас есть пример? В первом примере кода foreach не должен пропустить первый элемент, просто прочитайте его во второй раз. Я не понимаю, в какой ситуации это было бы невозможно. –
@ Мета-рыцарь: Я добавил пример, надеюсь, что это поможет. –