我可以从枚举中获取前n个元素,然后仍然使用枚举的其余部分吗?

时间:2014-04-01 23:22:51

标签: c# .net linq

假设我有IEnumerable<T>,我想获取第一个元素并将其余元素传递给其他代码。我可以使用Take(n)获取第一个 n 元素,但是如何在不导致枚举重新启动的情况下访问其余元素?

例如,假设我有一个方法ReadRecords,它接受​​CSV文件中的记录为IEnumerable<string>。现在假设在该方法中,我想读取第一条记录(标题),然后将剩余的记录传递给ReadDataRecords方法,该方法也需要IEnumerable<string>。像这样:

void ReadCsv(IEnumerable<string> records)
{
    var headerRecord = records.Take(1);
    var dataRecords = ???

    ReadDataRecords(dataRecords);
}

void ReadDataRecords(IEnumerable<string> records)
{
    // ...
}

如果我准备重新开始枚举,那么我可以使用dataRecords = records.Skip(1)。但是,我不想重新启动它 - 事实上,它可能无法重新启动。

那么,有没有办法获取第一个记录,然后是剩余的记录(除了将所有值读入新的集合并重新枚举它们)?

2 个答案:

答案 0 :(得分:14)

这是一个有趣的问题,我认为你可以使用这样的解决方法,而不是使用LINQ获取枚举器并使用它:

private void ReadCsv(IEnumerable<string> records)
{
     var enumerator = records.GetEnumerator();
     enumerator.MoveNext();
     var headerRecord = enumerator.Current;
     var dataRecords = GetRemainingRecords(enumerator);
}

public IEnumerable<string> GetRemainingRecords(IEnumerator<string> enumerator)
{
    while (enumerator.MoveNext())
    {
       if (enumerator.Current != null)
            yield return enumerator.Current;
    }
}

更新:根据您的评论,这里有更广泛的方式:

public static class CustomEnumerator
{
    private static int _counter = 0;
    private static IEnumerator enumerator;
    public static IEnumerable<T> GetRecords<T>(this IEnumerable<T> source)
    {
        if (enumerator == null) enumerator = source.GetEnumerator();

        if (_counter == 0)
        {
            enumerator.MoveNext();
            _counter++;
            yield return (T)enumerator.Current;
        }
        else
        {
            while (enumerator.MoveNext())
            {
                yield return (T)enumerator.Current;
            }
            _counter = 0;
            enumerator = null;
        }
    } 
}

用法:

private static void ReadCsv(IEnumerable<string> records)
{
     var headerRecord = records.GetRecords();
     var dataRecords = records.GetRecords();
}

答案 1 :(得分:3)

是的,使用IEnumerable中的IEnumerator,您可以保持方法调用的位置;

一个简单的例子;

public class Program
{
    static void Main(string[] args)
    {
        int[] arr = new [] {1, 2, 3};
        IEnumerator enumerator = arr.GetEnumerator();
        enumerator.MoveNext();
        Console.WriteLine(enumerator.Current);
        DoRest(enumerator);
    }

    static void DoRest(IEnumerator enumerator)
    {
        while (enumerator.MoveNext())
            Console.WriteLine(enumerator.Current);
    }
}