将数组拆分为块 - 有更快的方法吗?

2023-12-30

我正在寻找将数组拆分为固定大小的块的最快方法(当然,最后一个可以更小)。我浏览了整个网站,没有发现任何性能方面的比较,所以我写了它们,结果如下:

时间(以微秒为单位),平均值/误差/标准差

For int[]- 30.02 | 0.1002 | 0.0937

For IEnumerable<int>- 76.67 | 0.2146 | 0.2146 0.1902

Update:下面的版本(在 @Markus 的回答中)是 139.5 | 0.6702 | 0.5597

SO 上最受欢迎的方法,也是经常推荐的使用 LINQ 的方法GroupBy with index/chunkSize不行——267 微秒比上述任何一个实现都长太多了。

有没有更快的方法来分割数组?

附: 这是代码Array and IEnumerable<T>:

    /// <summary>
    /// Splits <paramref name="source"/> into chunks of size not greater than <paramref name="chunkMaxSize"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">Array to be split</param>
    /// <param name="chunkMaxSize">Max size of chunk</param>
    /// <returns><see cref="IEnumerable{T}"/> of <see cref="Array"/> of <typeparam name="T"/></returns>
    public static IEnumerable<T[]> AsChunks<T>(this T[] source, int chunkMaxSize)
    {
        var pos = 0;
        var sourceLength = source.Length;
        do
        {
            var len = Math.Min(pos + chunkMaxSize, sourceLength) - pos;
            if (len == 0)
            {
                yield break;;
            }
            var arr = new T[len];
            Array.Copy(source, pos, arr, 0, len);
            pos += len;
            yield return arr;
        } while (pos < sourceLength);
    }

    /// <summary>
    /// Splits <paramref name="source"/> into chunks of size not greater than <paramref name="chunkMaxSize"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"><see cref="IEnumerable{T}"/> to be split</param>
    /// <param name="chunkMaxSize">Max size of chunk</param>
    /// <returns><see cref="IEnumerable{T}"/> of <see cref="Array"/> of <typeparam name="T"/></returns>
    public static IEnumerable<T[]> AsChunks<T>(this IEnumerable<T> source, int chunkMaxSize)
    {
        var arr = new T[chunkMaxSize];
        var pos = 0;
        foreach (var item in source)
        {
            arr[pos++] = item;
            if (pos == chunkMaxSize)
            {
                yield return arr;
                arr = new T[chunkMaxSize];
                pos = 0;
            }
        }
        if (pos > 0)
        {
            Array.Resize(ref arr, pos);
            yield return arr;
        }
    }

P.P.S 带有 BenchmarkDotNet 测试的完整解决方案是在 GitHub 上 https://github.com/AlexSeleznyov/SplitToChunk.


不太确定这是如何叠加的(ArraySegment),但请尝试一下。我已经避免使用迭代器,但不确定这是否真的是一个好处。

public static IEnumerable<T[]> AsChunks<T>(
    this T[] source, int chunkMaxSize)
{
    var chunks = source.Length / chunkMaxSize;
    var leftOver = source.Length % chunkMaxSize;
    var result = new List<T[]>(chunks + 1);
    var offset = 0;

    for (var i = 0; i < chunks; i++)
    {
        result.Add(new ArraySegment<T>(source,
                                       offset, 
                                       chunkMaxSize).ToArray());
        offset += chunkMaxSize;
    }

    if (leftOver > 0)
    {
        result.Add(new ArraySegment<T>(source, 
                                       offset, 
                                       leftOver).ToArray());
    }

    return result;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将数组拆分为块 - 有更快的方法吗? 的相关文章