Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.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# 如何成批循环使用IEnumerable_C#_Ienumerable - Fatal编程技术网

C# 如何成批循环使用IEnumerable

C# 如何成批循环使用IEnumerable,c#,ienumerable,C#,Ienumerable,我正在开发一个c#程序,它有一个“IEnumerable users”,存储400万用户的ID。我需要循环遍历IEnumerable,每次提取一批1000个ID,以在另一个方法中执行一些操作 如何从Ienumerable开始一次提取1000个ID…做一些其他事情,然后获取下一批1000个ID,依此类推 这可能吗?最简单的方法可能就是使用LINQ中的方法: var batches = myEnumerable .Select((x, i) => new { x, i }) .

我正在开发一个c#程序,它有一个“IEnumerable users”,存储400万用户的ID。我需要循环遍历IEnumerable,每次提取一批1000个ID,以在另一个方法中执行一些操作

如何从Ienumerable开始一次提取1000个ID…做一些其他事情,然后获取下一批1000个ID,依此类推


这可能吗?

最简单的方法可能就是使用LINQ中的方法:

var batches = myEnumerable
    .Select((x, i) => new { x, i })
    .GroupBy(p => (p.i / 1000), (p, i) => p.x);
但是对于一个更复杂的解决方案,请参阅下面关于如何创建自己的扩展方法来实现这一点的内容。为子孙后代复制于此:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize)
{
    List<T> nextbatch = new List<T>(batchSize);
    foreach (T item in collection)
    {
        nextbatch.Add(item);
        if (nextbatch.Count == batchSize)
        {
            yield return nextbatch;
            nextbatch = new List<T>(); 
            // or nextbatch.Clear(); but see Servy's comment below
        }
    }

    if (nextbatch.Count > 0)
        yield return nextbatch;
}
公共静态IEnumerable批处理(此IEnumerable集合,int batchSize)
{
List nextbatch=新列表(批量大小);
foreach(集合中的T项)
{
下一批次添加(项目);
if(nextbatch.Count==batchSize)
{
下一批收益率;
nextbatch=新列表();
//或nextbatch.Clear();但请参见下面的Servy评论
}
}
如果(nextbatch.Count>0)
下一批收益率;
}

您可以使用Take和Skip可枚举扩展方法来实现这一点。有关用法签出的更多信息,请使用(可从NuGet获得):


听起来您需要对对象使用Skip和Take方法。例如:

users.Skip(1000).Take(1000)
这将跳过前1000个,然后取下1000个。你只需要增加每次通话跳过的次数

您可以使用带有Skip参数的整数变量,并可以调整跳过的数量。然后可以在方法中调用它

public IEnumerable<user> GetBatch(int pageNumber)
{
    return users.Skip(pageNumber * 1000).Take(1000);
}
public IEnumerable GetBatch(int页码)
{
返回用户。跳过(页码*1000)。获取(1000);
}

您可以使用
Take运算符linq

链接:

尝试使用以下链接:

  public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(
        this IEnumerable<TSource> source,
        int batchSize)
    {
        var batch = new List<TSource>();
        foreach (var item in source)
        {
            batch.Add(item);
            if (batch.Count == batchSize)
            {
                 yield return batch;
                 batch = new List<TSource>();
            }
        }

        if (batch.Any()) yield return batch;
    }

类似这样的方法会奏效:

List<MyClass> batch = new List<MyClass>();
foreach (MyClass item in items)
{
    batch.Add(item);

    if (batch.Count == 1000)
    {
        // Perform operation on batch
        batch.Clear();
    }
}

// Process last batch
if (batch.Any())
{
    // Perform operation on batch
}
List批处理=新建列表();
foreach(项目中的MyClass项目)
{
批次。添加(项目);
如果(batch.Count==1000)
{
//对批执行操作
batch.Clear();
}
}
//处理最后一批
if(batch.Any())
{
//对批执行操作
}
您可以将其概括为一个通用方法,如下所示:

static void PerformBatchedOperation<T>(IEnumerable<T> items, 
                                       Action<IEnumerable<T>> operation, 
                                       int batchSize)
{
    List<T> batch = new List<T>();
    foreach (T item in items)
    {
        batch.Add(item);

        if (batch.Count == batchSize)
        {
            operation(batch);
            batch.Clear();
        }
    }

    // Process last batch
    if (batch.Any())
    {
        operation(batch);
    }
}
static void performbatch操作(IEnumerable items,
行动行动,,
int批处理大小)
{
列表批次=新列表();
foreach(项目中的T项目)
{
批次。添加(项目);
if(batch.Count==batchSize)
{
操作(批量);
batch.Clear();
}
}
//处理最后一批
if(batch.Any())
{
操作(批量);
}
}
怎么样

int batchsize = 5;
List<string> colection = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};
for (int x = 0; x < Math.Ceiling((decimal)colection.Count / batchsize); x++)
{
    var t = colection.Skip(x * batchsize).Take(batchsize);
}
int batchsize=5;
列表集合=新列表{“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”、“10”、“11”、“12”};
对于(int x=0;x<数学上限((十进制)colection.Count/batchsize);x++)
{
var t=collection.Skip(x*batchsize).Take(batchsize);
}

在流媒体环境中,枚举器可能会在批处理的中间被阻塞,仅仅因为该值尚未产生(产率),所以有一个超时方法是有用的,以便在给定的时间之后产生最后一批。例如,我用它来跟踪MongoDB中的光标。这有点复杂,因为枚举必须在另一个线程中完成

    public static IEnumerable<List<T>> TimedBatch<T>(this IEnumerable<T> collection, double timeoutMilliseconds, long maxItems)
    {
        object _lock = new object();
        List<T> batch = new List<T>();
        AutoResetEvent yieldEventTriggered = new AutoResetEvent(false);
        AutoResetEvent yieldEventFinished = new AutoResetEvent(false);
        bool yieldEventTriggering = false; 

        var task = Task.Run(delegate
        {
            foreach (T item in collection)
            {
                lock (_lock)
                {
                    batch.Add(item);

                    if (batch.Count == maxItems)
                    {
                        yieldEventTriggering = true;
                        yieldEventTriggered.Set();
                    }
                }

                if (yieldEventTriggering)
                {
                    yieldEventFinished.WaitOne(); //wait for the yield to finish, and batch to be cleaned 
                    yieldEventTriggering = false;
                }
            }
        });

        while (!task.IsCompleted)
        {
            //Wait for the event to be triggered, or the timeout to finish
            yieldEventTriggered.WaitOne(TimeSpan.FromMilliseconds(timeoutMilliseconds));
            lock (_lock)
            {
                if (batch.Count > 0) //yield return only if the batch accumulated something
                {
                    yield return batch;
                    batch.Clear();
                    yieldEventFinished.Set();
                }
            }
        }
        task.Wait();
    }
public静态IEnumerable TimedBatch(此IEnumerable集合,双timeoutmillizes,长maxItems)
{
对象_lock=新对象();
列表批次=新列表();
AutoResetEvent yieldEventTriggered=新的AutoResetEvent(假);
AutoResetEvent yieldEventFinished=新的AutoResetEvent(假);
bool yieldEventTriggering=false;
var task=task.Run(委托
{
foreach(集合中的T项)
{
锁
{
批次。添加(项目);
if(batch.Count==maxItems)
{
yieldEventTriggering=true;
yieldEventTriggered.Set();
}
}
如果(yieldEventTriggering)
{
yieldEventFinished.WaitOne();//等待成品完成,并清理批次
yieldEventTriggering=false;
}
}
});
而(!task.IsCompleted)
{
//等待事件被触发,或等待超时完成
yieldEventTriggered.WaitOne(TimeSpan.frommilluses(timeoutmiluses));
锁
{
if(batch.Count>0)//仅当批次累积了某些内容时才返回产量
{
退货批量;
batch.Clear();
yieldEventFinished.Set();
}
}
}
task.Wait();
}

是的,但可能效率不高……我知道可以使用take,但当我获取1000条记录时,如何从上一条记录中再获取1000条point@user1526912-
跳过(i*1000)。在i=0,1,2时取(1000)
,…@user1526912如果您使用的是.Net framework 4.0或更高版本,您可以使用多核处理器来稍微快速地处理它。这对于LINQ to somequeryprovider非常有用,可以在其中高效地实现跳过。对于LINQ To对象,这将对每个批都迭代源序列一次,但会花费大量时间在
Skip
中,因为它对任意序列都不有效。我正要回答这个问题。不要重新发明轮子,使用MoreLinq的批处理方法;-)@Meta Knight是的,我使用他们的MaxBy、DistinctBy、Batch和其他方法。发明新车比改造车轮要好:)值得注意的是,
Select
专门用于向调用者隐藏底层数组(并不是说他们在这一点上可以做很多)。
List<MyClass> batch = new List<MyClass>();
foreach (MyClass item in items)
{
    batch.Add(item);

    if (batch.Count == 1000)
    {
        // Perform operation on batch
        batch.Clear();
    }
}

// Process last batch
if (batch.Any())
{
    // Perform operation on batch
}
static void PerformBatchedOperation<T>(IEnumerable<T> items, 
                                       Action<IEnumerable<T>> operation, 
                                       int batchSize)
{
    List<T> batch = new List<T>();
    foreach (T item in items)
    {
        batch.Add(item);

        if (batch.Count == batchSize)
        {
            operation(batch);
            batch.Clear();
        }
    }

    // Process last batch
    if (batch.Any())
    {
        operation(batch);
    }
}
int batchsize = 5;
List<string> colection = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};
for (int x = 0; x < Math.Ceiling((decimal)colection.Count / batchsize); x++)
{
    var t = colection.Skip(x * batchsize).Take(batchsize);
}
    public static IEnumerable<List<T>> TimedBatch<T>(this IEnumerable<T> collection, double timeoutMilliseconds, long maxItems)
    {
        object _lock = new object();
        List<T> batch = new List<T>();
        AutoResetEvent yieldEventTriggered = new AutoResetEvent(false);
        AutoResetEvent yieldEventFinished = new AutoResetEvent(false);
        bool yieldEventTriggering = false; 

        var task = Task.Run(delegate
        {
            foreach (T item in collection)
            {
                lock (_lock)
                {
                    batch.Add(item);

                    if (batch.Count == maxItems)
                    {
                        yieldEventTriggering = true;
                        yieldEventTriggered.Set();
                    }
                }

                if (yieldEventTriggering)
                {
                    yieldEventFinished.WaitOne(); //wait for the yield to finish, and batch to be cleaned 
                    yieldEventTriggering = false;
                }
            }
        });

        while (!task.IsCompleted)
        {
            //Wait for the event to be triggered, or the timeout to finish
            yieldEventTriggered.WaitOne(TimeSpan.FromMilliseconds(timeoutMilliseconds));
            lock (_lock)
            {
                if (batch.Count > 0) //yield return only if the batch accumulated something
                {
                    yield return batch;
                    batch.Clear();
                    yieldEventFinished.Set();
                }
            }
        }
        task.Wait();
    }