У меня есть IEnumerable T. Я хочу пропустить определенное количество T, но в процессе я также хочу прочитать эти T. Вы можете прочитать Ts с помощью Take() и пропустить их с помощью Skip(), но что повлечет за собой множественные перечисления.
Мне нужно прочитать N элементов, обработать их, а затем вернуть все непрочитанные элементы в виде IEnumerable в одном перечислении.
Изменение: я пытаюсь передать IEnumerable методу, который принимает Stream-подобный. А именно, я должен реализовать только метод
public int Read(T[] readBuffer, int offset, int count)
Проблема в том, что мне нужно заранее перечислить прошедшие данные, чтобы сохранить позицию, а также прочитать данные, которые нужно передать обратно во входном буфере.
До сих пор я пробовал это:
public static IEnumerable<T> SkipTake<T>(this IEnumerable<T> input, int num, Action<List<T>> take)
{
var enumerator = input.GetEnumerator();
var chunk = new List<T>();
for (int i = 0; i < num; ++num)
{
chunk.Add(enumerator.Current);
if (!enumerator.MoveNext())
break;
}
take(chunk);
yield return enumerator.Current;
while (enumerator.MoveNext())
yield return enumerator.Current;
}
Не много удачи.
Похоже, что ваша реализация не вызывает MoveNext()
в нужное время. Вы должны вызвать MoveNext()
прежде чем вы сможете получить Current
элемент:
public static IEnumerable<T> SkipTake<T>(this IEnumerable<T> input, int num, Action<List<T>> take)
{
var enumerator = input.GetEnumerator();
var chunk = new List<T>();
for (int i = 0; i < num; ++num)
{
if (!enumerator.MoveNext())
break;
chunk.Add(enumerator.Current);
}
take(chunk);
while (enumerator.MoveNext())
yield return enumerator.Current;
}
EDIT: просто для того, чтобы это было ясно, вот пример использования:
var list = new List<string>() {"This", "is", "an", "example", "!"};
var res = list.SkipTake(2, chunk =>
{
Console.WriteLine(chunk.Count());
});
Console.WriteLine(res.Count());
Выход
2 3
и коллекции содержат
{"Это"}
а также
{"пример", "!"}
соответственно, и первоначальный list
коллекции не был изменен.