Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以从枚举中获取前n个元素,然后仍然使用枚举的其余部分吗?_C#_.net_Linq - Fatal编程技术网

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

C# 我可以从枚举中获取前n个元素,然后仍然使用枚举的其余部分吗?,c#,.net,linq,C#,.net,Linq,假设我有一个IEnumerable,我想获取第一个元素并将其余元素传递给其他代码。我可以使用Take(n)获取前n个元素,但是如何在不导致枚举重新启动的情况下访问其余元素呢 例如,假设我有一个方法ReadRecords,它将CSV文件中的记录作为IEnumerable接受。现在假设在该方法中,我想读取第一条记录(标题),然后将剩余的记录传递给ReadDataRecords方法,该方法也采用IEnumerable。像这样: void ReadCsv(IEnumerable<string>

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

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

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

    ReadDataRecords(dataRecords);
}

void ReadDataRecords(IEnumerable<string> records)
{
    // ...
}
void ReadCsv(IEnumerable记录)
{
var headerRecord=records.Take(1);
var数据记录=???
ReadDataRecords(数据记录);
}
作废ReadDataRecords(IEnumerable记录)
{
// ...
}
如果我准备重新启动枚举,那么我可以使用
dataRecords=records.Skip(1)
。然而,我不想重新启动它——事实上,它可能无法重新启动


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

这是一个有趣的问题,我认为您可以使用类似这样的解决方法,而不是使用
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;
    }
}
private void ReadCsv(IEnumerable记录)
{
var枚举器=记录。GetEnumerator();
枚举数。MoveNext();
var headerRecord=枚举器.Current;
var dataRecords=GetRemainingRecords(枚举器);
}
公共IEnumerable GetRemainingRecords(IEnumerator枚举器)
{
while(枚举数.MoveNext())
{
if(enumerator.Current!=null)
产生返回枚举数。当前;
}
}
更新:根据您的评论,这里有一种更广泛的方法:

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;
        }
    } 
}
公共静态类CustomEnumerator
{
专用静态int_计数器=0;
私有静态IEnumerator枚举器;
公共静态IEnumerable GetRecords(此IEnumerable源)
{
if(enumerator==null)enumerator=source.GetEnumerator();
如果(_计数器==0)
{
枚举数。MoveNext();
_计数器++;
产生返回(T)枚举数.Current;
}
其他的
{
while(枚举数.MoveNext())
{
产生返回(T)枚举数.Current;
}
_计数器=0;
枚举数=null;
}
} 
}
用法:

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

是的,使用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);
    }
}

如果你只需要跳过一个,那有什么大不了的?只需再次枚举并跳过一个?如果您需要,MoreLinq中有很好的解决方案。关于特殊大小写的第一个/最后一个元素也有几个问题。@Blam:如果枚举是通过枚举内存中的某些内容(例如枚举列表中的项目)创建的,则为“是”。但是,如果枚举无法重新启动,或者执行起来非常昂贵,该怎么办?我不明白为什么当我只想精确地获取每个项目一次时,就必须有两个枚举。没问题。感谢您提醒我,枚举数仍然存在于所有可爱的语法之上,这些语法不断添加到框架中,并且仍然可以随时加以利用+1谢谢。我想我可以创建一个通用类来获取IEnumerable的余数。顺便问一下,为什么在循环中使用空测试?似乎是多余的…如果我说我想调用一个方法ProcessHeaderRecords,它接受IEnumerable,然后是ProcessDataRecords,再次接受IEnumerable,那又怎么样?我几乎可以看出你的答案是如何扩展的,但必须有某种东西来坚持在ProcessDataRecords读取任何内容之前ProcessHeaderRecords读取了N条记录,因为它们将共享同一个枚举数…@GaryMcGill我明白你的意思,请看我的第二个解决方案。我认为它正在做您想要的事情。看起来,
\u counter
(应该是
bool
)与
枚举器
null
是多余的。谢谢,但我确实希望能够调用一个接受IEnumerable的方法,以便保留更好的API。对不起,我没说清楚。