将数组拆分成块-有更快的方法吗? [英] Split array into chunks - is there faster method?

查看:61
本文介绍了将数组拆分成块-有更快的方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking for the quickest method to split an array into chunks of fixed size (last one can be smaller, of course). I've looked throughout the site and didn't find any performance-wise comparisons, so I wrote them, and here are the results:


以毫秒为单位的时间,均值/错误/标准差

Time in microseconds, mean/error/stddev

对于 int [] -30.02 | 0.1002 | 0.0937

For int[] - 30.02 | 0.1002 | 0.0937

对于 IEnumerable< int> -76.67 | 0.2146 | 0.1902

For IEnumerable<int> - 76.67 | 0.2146 | 0.1902

更新:以下版本(在@Markus的回答中)为139.5 | 0.6702 | 0.5597

Update: Version below (in @Markus' answer) is 139.5 | 0.6702 | 0.5597

在SO上最受欢迎,也是经常推荐的方法,以结合使用 index来使用LINQ的 GroupBy / chunkSize 是不可行的-267微秒远远超过上述任何一种实现。

Most popular here on SO and frequently recommended method to use LINQ's GroupBy with index/chunkSize is a no go - 267 microseconds is way too greater than either of aforementioned implementations.

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

Is there any faster way to split arrays?

PS
这是 Array 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;
        }
    }

PPS带有BenchmarkDotNet测试的完整解决方案是在GitHub

P.P.S Complete solution with BenchmarkDotNet tests is on GitHub.

推荐答案

不太确定如何堆叠( ArraySegment ),但请尝试一下。我避免使用迭代器,但不确定在这里是否真的有用。

Not really sure how this stacks up (ArraySegment), but give it a try. I've avoided using iterators but not really sure if that is really a gain here.

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;
}

这篇关于将数组拆分成块-有更快的方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆