C#将二维数组分块为批次

时间:2019-03-29 13:51:27

标签: c# arrays multidimensional-array

我有一个二维object[,]数组,其中包含行和列的矩阵(object[nRows, nColumns])。

我想将其分块为一批行-例如我可以枚举成批的1,000行。

总而言之,我正在寻找能执行以下操作但针对二维数组(source)的C#代码:

private IEnumerable<T[]> SplitArray<T>(T[] sourceArray, int rangeLength)
{
    int startIndex = 0;

    do
    {
        T[] range = new T[Math.Min(rangeLength, sourceArray.Length - startIndex)];
        Array.Copy(sourceArray, startIndex, range, 0, range.Length);
        startIndex += rangeLength;
        yield return range;
    }
    while (startIndex < sourceArray.Length);            
}

这种为[,]数组修改代码的尝试失败了-第一次迭代后,行/列开始变得混乱:

        private IEnumerable<T[,]> SplitArray<T>(T[,] sourceArray, int rangeLength)
        {
            int startIndex = 0;

            do
            {
                T[,] range = new T[Math.Min(rangeLength, sourceArray.GetLength(0) - startIndex), sourceArray.GetLength(1)];
                Array.Copy(sourceArray, startIndex, range, 0, range.Length);
                startIndex += rangeLength;
                yield return range;
            }
            while (startIndex < sourceArray.GetLength(0));
        }

3 个答案:

答案 0 :(得分:2)

这将解决您的代码问题。由于Array.Copy威胁数组是一维的,因此您必须乘以列数才能获得某些位置的元素总数:

private IEnumerable<T[,]> SplitArray<T>(T[,] sourceArray, int rangeLength)
{
    int startIndex = 0;
    do
    {
        T[,] range = new T[Math.Min(rangeLength, sourceArray.GetLength(0) - startIndex/sourceArray.GetLength(1)), sourceArray.GetLength(1)];
        Array.Copy(sourceArray, startIndex, range, 0, range.Length);
        startIndex += rangeLength*sourceArray.GetLength(1);
        yield return range;
    }
    while (startIndex < sourceArray.Length);
}

答案 1 :(得分:1)

通过使用GetLength(int dimension),您可以查看数组的特定维的长度,然后对其进行迭代。您还需要将其他维度用作常量,并确保整个内容与Array.Rank值匹配。从那里,只需通过Array.GetValue(int[])查找值。由于Array不是通用的,因此可能会有点困难:

public static IEnumerable<T> GetRow<T>(this Array source, int dimension, params int[] fixedDimensions)
{
    if(source == null) throw new ArgumentNullException(nameof(source));
    if(!typeof(T).IsAssignableFrom(source.GetType().GetElementType()) throw new OperationException($"Cannot return row of type {typeof(T)} from array of type {source.GetType().GetElementType()}");

    if(fixedDimensions == null) fixedDimensions = new T[0];
    if(source.Rank != fixedDimensions.Length + 1) throw new ArgumentException("Fixed dimensions must have exactly one fewer elements than dimensions in source", nameof(fixedDimensions));
    if(dimension > source.Rank) throw new ArgumentException($"Cannot take dimension {dimension} of an array with {source.Rank} dimensions!", nameof(dimension));
    if(dimension < 0) throw new ArgumentException("Cannot take a negative dimension", nameof(dimension));

    var coords = dimension == source.Rank
         ? fixedDimensions
            .Concat(new [] { 0 })
            .ToArray()
        : fixedDimensions
            .Take(dimension)
            .Concat(new [] { 0 })
            .Concat(fixedDimensions.Skip(dimension))
            .ToArray();

    var length = source.GetLength(dimension);
    for(; coords[dimension] < length; coords[dimension]++)
    {
        yield return (T)source.GetValue(coords);
    }
}

答案 2 :(得分:1)

我认为您正在寻找这样的东西:

private static List<T[]> SplitArray<T>(T[,] sourceArray)
{
    List<T[]> result = new List<T[]>();
    int rowCount = sourceArray.GetLength(0);
    for (int i = 0; i < rowCount; i++)
    {
        result.Add(GetRow(sourceArray, i));
    }

    return result;
}

private static T[] GetRow<T>(T[,] sourceArray, int rownumber)
{
    int columnCount = sourceArray.GetLength(1);
    var row = new T[columnCount];
    for (int i = 0; i < columnCount; i++)
    {
        row[i] = sourceArray[rownumber, i];
    }
    return row;
}