tags:

views:

131

answers:

3

Given a large array how can it be split into smaller arrays with the size of the smaller arrays specified as an argument of the method?

For instance, given numbers, what would Split's implementation be?

int[] numbers = new int[7845];

int[][] sectionedNumbers = numbers.Split(1000);

sectionedNumbers.Length; //outputs 8
sectionedNumbers[7].Length; //outputs 845
+1  A: 

Reed beat me to it, but here's my method anyway:

public int[][] Split(int[] source, int size)
{
    int fullArrayCount = source.Length / size;
    int totalArrayCount = fullArrayCount;
    int remainder = source.Length - (fullArrayCount * size);
    if (remainder > 0)
    {
        totalArrayCount++;
    }
    int[][] output = new int[totalArrayCount][];
    for (int i = 0; i < fullArrayCount; i++)
    {
        output[i] = new int[size];
        Array.Copy(source, i * size, output[i], 0, size);
    }
    if (totalArrayCount != fullArrayCount)
    {
        output[fullArrayCount] = new int[remainder];
        Array.Copy(source, fullArrayCount * size,
            output[fullArrayCount], 0, remainder);
    }

    return output;
}
MusiGenesis
+4  A: 

You can do it with an extension method:

using System;

static class Program
{
    static T[][] Split<T>(this T[] arrayIn, int length)
    {
        bool even = arrayIn.Length%length == 0;
        int totalLength = arrayIn.Length/length;
        if (!even)
            totalLength++;

        T[][] newArray = new T[totalLength][];
        for (int i = 0; i < totalLength;++i )
        {
            int allocLength = length;
            if (!even && i == totalLength - 1)
                allocLength = arrayIn.Length % length;

            newArray[i] = new T[allocLength];
            Array.Copy(arrayIn, i * length, newArray[i], 0, allocLength);
        }
        return newArray;
    }

    static void Main(string[] args)
    {
        int[] numbers = new int[8010];
        for (int i = 0; i < numbers.Length; ++i)
            numbers[i] = i;

        int[][] sectionedNumbers = numbers.Split(1000);

        Console.WriteLine("{0}", sectionedNumbers.Length);
        Console.WriteLine("{0}", sectionedNumbers[7].Length);
        Console.WriteLine("{0}", sectionedNumbers[1][0]);
        Console.WriteLine("{0}", sectionedNumbers[7][298]);
        Console.ReadKey();
    } 
}

This prints:

9
1000
1000
7298
Reed Copsey
+1 for speed. Blah blah blah so I can be 15 characters.
MusiGenesis
instead of using 'even' variable, just use: int totalLength = (arrayIn.Length + length - 1)/length;it slightly shorter and slightly faster :)
Alex
@Alex: It would be, except that I use it again later, so precalculating is better.
Reed Copsey
Thanks Reed, this is almost identical to the method I came up with. Stackoverflow is now a unit test.
Bob
+1  A: 

This isn't necessarily a good idea, but here's an implementation that generalises this splitting operation to IEnumerable<T>, returning an IEnumerable<IEnumerable<T>>.

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> input, int size)
{
    return input.Select((a, i) => new { Item = a, Index = i })
                .GroupBy( b => (b.Index / size))
                .Select(c => c.Select(d => d.Item));
}
stevemegson