.net 将数组拆分为块-是否有更快的方法?

9cbw7uwe  于 2022-11-26  发布在  .NET
关注(0)|答案(4)|浏览(164)

我正在寻找最快的方法来将数组分割成固定大小的块(当然,最后一个块可以更小)。我在整个站点中查找,没有找到任何性能方面的比较,所以我编写了它们,下面是结果:
以微秒为单位的时间,平均值/误差/标准偏差
对于int[]- 30.02|千分之二|0.0937分
对于IEnumerable<int>- 76.67|零点二一四六|0.1902英寸

更新:以下版本(@Markus的答案)为139.5| 0.6702分|千分之五五九七

这里最流行的SO和经常推荐的方法使用LINQ的GroupByindex/chunkSize是一个不去- 267微秒是太多的方式比上述任何一个实现。
是否有更快的方法来拆分阵列?
P.S.这是ArrayIEnumerable<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测试的完整解决方案为on GitHub

yyyllmsg

yyyllmsg1#

我不太确定这是如何叠加的(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;
}
hgc7kmma

hgc7kmma2#

我使用了此代码:
来源:http://blogs.msdn.com/b/pfxteam/archive/2012/11/16/plinq-and-int32-maxvalue.aspx

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize) {
    if (batchSize <= 0) {
        throw new ArgumentOutOfRangeException(nameof(batchSize));
    }
    using(var enumerator = source.GetEnumerator()) {
        while (enumerator.MoveNext()) {
            yield return YieldBatchElements(enumerator, batchSize - 1);
        }
    }
}

private static IEnumerable<T> YieldBatchElements<T>(IEnumerator<T> source, int batchSize) {
    yield return source.Current;
    for (var i = 0; i < batchSize && source.MoveNext(); i++) {
        yield return source.Current;
    }
}
jvlzgdj9

jvlzgdj93#

您可以使用这几行代码

int chunkSize = 4;
                int skipIndex = 0;
                string[] words = { "one", "two", "three", "four", "five", "six" };
                string[][] chunckResult = new string[words.Length][];

                for (int index = 0; index < words.Length; index++)
                {
                    chunckResult[index] = words.Skip(skipIndex).Take(chunkSize).ToArray();
                    skipIndex += chunkSize;
                    if (skipIndex == words.Length)
                    {
                        break;
                    }
                }
kh212irz

kh212irz4#

public static List<someObject[]> splitArrayIntoSmallerArrays<someObject>(someObject[] arrayOfSomeObject, int chunkSize)
{
    var output = new List<someObject[]>();
    var newestArray = new List<someObject>();
    for (int i = 0, loopTo = arrayOfSomeObject.Count() - 1; i <= loopTo; i++)
    {

        newestArray.Add(arrayOfSomeObject[i]);
        if (newestArray.Count == chunkSize)
        {
            output.Add(newestArray.ToArray());
            newestArray = new List<someObject>();
        }
    }
    output.Add(newestArray.ToArray());
    return output;
}

相关问题