Split a List into smaller lists of N size

前端 未结 17 1853
后悔当初
后悔当初 2020-11-22 16:55

I am attempting to split a list into a series of smaller lists.

My Problem: My function to split lists doesn\'t split them into lists of the correct

17条回答
  •  盖世英雄少女心
    2020-11-22 17:56

    Based on Dimitry Pavlov answere I would remove .ToList(). And also avoid the anonymous class. Instead I like to use a struct which does not require a heap memory allocation. (A ValueTuple would also do job.)

    public static IEnumerable> ChunkBy(this IEnumerable source, int chunkSize)
    {
        if (source is null)
        {
            throw new ArgumentNullException(nameof(source));
        }
        if (chunkSize <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(chunkSize), chunkSize, "The argument must be greater than zero.");
        }
    
        return source
            .Select((x, i) => new ChunkedValue(x, i / chunkSize))
            .GroupBy(cv => cv.ChunkIndex)
            .Select(g => g.Select(cv => cv.Value));
    } 
    
    [StructLayout(LayoutKind.Auto)]
    [DebuggerDisplay("{" + nameof(ChunkedValue.ChunkIndex) + "}: {" + nameof(ChunkedValue.Value) + "}")]
    private struct ChunkedValue
    {
        public ChunkedValue(T value, int chunkIndex)
        {
            this.ChunkIndex = chunkIndex;
            this.Value = value;
        }
    
        public int ChunkIndex { get; }
    
        public T Value { get; }
    }
    

    This can be used like the following which only iterates over the collection once and also does not allocate any significant memory.

    int chunkSize = 30;
    foreach (var chunk in collection.ChunkBy(chunkSize))
    {
        foreach (var item in chunk)
        {
            // your code for item here.
        }
    }
    

    If a concrete list is actually needed then I would do it like this:

    int chunkSize = 30;
    var chunkList = new List>();
    foreach (var chunk in collection.ChunkBy(chunkSize))
    {
        // create a list with the correct capacity to be able to contain one chunk
        // to avoid the resizing (additional memory allocation and memory copy) within the List.
        var list = new List(chunkSize);
        list.AddRange(chunk);
        chunkList.Add(list);
    }
    

提交回复
热议问题