简体   繁体   English

LINQ:从集合中获取一系列元素

[英]LINQ: take a sequence of elements from a collection

I have a collection of objects and need to take batches of 100 objects and do some work with them until there are no objects left to process. 我有一个对象集合,需要接受100个对象的批处理,然后对它们进行一些处理,直到没有任何对象需要处理。

Instead of looping through each item and grabbing 100 elements then the next hundred etc is there a nicer way of doing it with linq? 而不是循环每个项目并抓住100个元素,然后下一百个等有一个更好的方式与linq做它?

Many thanks 非常感谢

static void test(IEnumerable<object> objects)
{
    while (objects.Any())
    {
        foreach (object o in objects.Take(100))
        {
        }
        objects = objects.Skip(100); 
    }
}

:) :)

int batchSize = 100;
var batched = yourCollection.Select((x, i) => new { Val = x, Idx = i })
                            .GroupBy(x => x.Idx / batchSize,
                                     (k, g) => g.Select(x => x.Val));

// and then to demonstrate...
foreach (var batch in batched)
{
    Console.WriteLine("Processing batch...");

    foreach (var item in batch)
    {
        Console.WriteLine("Processing item: " + item);
    }
}

This will partition the list into a list of lists of however many items you specify. 这会将列表分区为您指定的许多项目的列表。

public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int size)
{
    int i = 0;
    List<T> list = new List<T>(size);
    foreach (T item in source)
    {
        list.Add(item);
        if (++i == size)
        {
            yield return list;
            list = new List<T>(size);
            i = 0;
        }
    }
    if (list.Count > 0)
        yield return list;
}

I don't think linq is really suitable for this sort of processing - it is mainly useful for performing operations on whole sequences rather than splitting or modifying them. 我不认为linq真的适合这种处理 - 它主要用于对整个序列执行操作而不是拆分或修改它们。 I would do this by accessing the underlying IEnumerator<T> since any method using Take and Skip are going to be quite inefficient. 我会通过访问底层的IEnumerator<T>来做到这一点,因为任何使用TakeSkip方法效率都会非常低。

public static void Batch<T>(this IEnumerable<T> items, int batchSize, Action<IEnumerable<T>> batchAction)
{
    if (batchSize < 1) throw new ArgumentException();

    List<T> buffer = new List<T>();
    using (var enumerator = (items ?? Enumerable.Empty<T>()).GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            buffer.Add(enumerator.Current);
            if (buffer.Count == batchSize)
            {
                batchAction(buffer);
                buffer.Clear();
            }
        }

        //execute for remaining items
        if (buffer.Count > 0)
        {
            batchAction(buffer);
        }
    }
}
var batchSize = 100;
for (var i = 0; i < Math.Ceiling(yourCollection.Count() / (decimal)batchSize); i++)
{
    var batch = yourCollection
        .Skip(i*batchSize)
        .Take(batchSize);

    // Do something with batch
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM