我如何组织一个可枚举的?

Tri*_*Gao 15 c# linq ienumerable

我需要一个优雅的方法,它采用一个可枚举的方法,并获得可枚举的枚举数,每个元素中包含相同数量的元素但最后一个:

public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, Int32 chunkSize)
{
    // TODO: code that chunks
}
Run Code Online (Sandbox Code Playgroud)

这是我尝试过的:

    public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, Int32 chunkSize)
    {
        var count = values.Count();
        var numberOfFullChunks = count / chunkSize;
        var lastChunkSize = count % chunkSize;
        for (var chunkIndex = 0; chunkSize < numberOfFullChunks; chunkSize++)
        {
            yield return values.Skip(chunkSize * chunkIndex).Take(chunkSize);
        }
        if (lastChunkSize > 0)
        {
            yield return values.Skip(chunkSize * count).Take(lastChunkSize);
        }
    }
Run Code Online (Sandbox Code Playgroud)

更新 刚发现有一个关于将列表拆分列表拆分为LINQ的子列表的类似主题

dan*_*era 25

>= .Net 6

内置Enumerable.Chunk方法:

// Giving an enumerable
var e = Enumerable.Range(1, 999);

// Here it is. Enjoy :)
var chunks = e.Chunk(29);

// Sample, iterating over chunks
foreach(var chunk in chunks) // for each chunk
{
    foreach(var item in chunk) // for each item in a chunk
    {
        Console.WriteLine(item);
    }
}
Run Code Online (Sandbox Code Playgroud)

<.Net 6?

将MS Chunk 源代码复制并粘贴到您的项目中。只需几行代码。


spe*_*der 16

如果不考虑内存消耗,那么这样吗?

static class Ex
{
    public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(
        this IEnumerable<TValue> values, 
        Int32 chunkSize)
    {
        return values
               .Select((v, i) => new {v, groupIndex = i / chunkSize})
               .GroupBy(x => x.groupIndex)
               .Select(g => g.Select(x => x.v));
    }
}
Run Code Online (Sandbox Code Playgroud)

否则,您可以使用yield关键字获得创意,如下所示:

static class Ex
{
    public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(
                    this IEnumerable<TValue> values, 
                    Int32 chunkSize)
    {
        using(var enumerator = values.GetEnumerator())
        {
            while(enumerator.MoveNext())
            {
                yield return GetChunk(enumerator, chunkSize).ToList();
            }
        }
    }
    private static IEnumerable<T> GetChunk<T>(
                     IEnumerator<T> enumerator,
                     int chunkSize)
    {
        do{
            yield return enumerator.Current;
        }while(--chunkSize > 0 && enumerator.MoveNext());
    }
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*Tom 8

public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
    while (source.Any())
    {
        yield return source.Take(chunksize);
        source = source.Skip(chunksize);
    }
}
Run Code Online (Sandbox Code Playgroud)